Application of runtime mechanism in OBJECTIVE-C

Source: Internet
Author: User


Application of runtime mechanism in OBJECTIVE-CFirst, the initial knowledge of the runtime


Objective-c is a dynamic language, the so-called dynamic language, is in the execution of the program dynamically determine the variable type, the implementation of variable type corresponding method. Therefore, the technique of string mapping classes is used in Object-c to dynamically create class objects. Because of the dynamic language characteristics of OC, we can change the object's variables and even methods dynamically when the program is running, which is what we call the runtime mechanism.


Second, do you have any way to manipulate such variables?


First, let's take a look at an example where I created a MyObject class:


//.h===========================
@interface MyObject : NSObject
{
    @private
    int privateOne;
    NSString * privateTow;;
}
@end
//=============================
//.m===========================
@interface MyObject()
{
    @private
    NSString * privateThree;
}
@end
@implementation MyObject
- (instancetype)init
{
    self = [super init];
    if (self) {
        privateOne=1;
        [email protected]"Tow";
        [email protected]"Three";
    }
    return self;
}
-(NSString *)description{
    return [NSString stringWithFormat:@"one=%d\ntow=%@\nthree=%@\n",privateOne,privateTow,privateThree];
}
@end
//=============================


This class is quite safe, first of all, in the header file does not provide any method interface, we have no way to use dot syntax to do any operation, Privateone and Privatetow two variables, although declared in the header file, but is a private type, through the way of pointers we can see them, But you can't do anything to read the changes, the following are the hints in Xcode:











He will tell us that this is a private variable that we cannot use. For Privatethree, we are helpless, not only can not use, we can not even see its existence. So what are some of the ways you can manipulate these variables? Yes, it's time to show the real technology: runtime!


third, get the variable list of the object through the runtime


To manipulate the variables of the object, we should first capture these variables, so that they have no place to hide. Whether the declaration is in the header file or the implementation file, whether the type is public or private, as long as the variable is declared, the system allocates space for it, we can capture it through the runtime mechanism, the code is as follows:


#import "ViewController.h"
#import "MyObject.h"
// Contains runtime header files
#import <objc / runtime.h>
@interface ViewController ()
@end
@implementation ViewController
-(void) viewDidLoad {
    [super viewDidLoad];
    // We first declare an unsigned int pointer and allocate memory for it
    unsigned int * count = malloc (sizeof (unsigned int));
    // Call the runtime method
    // Ivar: the object content object returned by the method, here will return a pointer of type Ivar
    // class_copyIvarList method can capture all the variables of the class, and store the number of variables in an unsigned int pointer
    Ivar * mem = class_copyIvarList ([MyObject class], count);
    // traverse
    for (int i = 0; i <* count; i ++) {
        // traverse by moving the pointer
        Ivar var = * (mem + i);
        // Get the name of the variable
        const char * name = ivar_getName (var);
        // Get the type of the variable
        const char * type = ivar_getTypeEncoding (var);
        NSLog (@ "% s:% s \ n", name, type);
    }
    // Free up memory
    free (count);
    // Pay attention to handling wild pointers
    count = nil;
}
-(void) didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end


The results are printed as follows, where I represents the int type :






is not a little surprised, no matter where the variable, as long as it is in, let it nowhere to hide.


Four, let me find you, let me change you!


It may not be possible to get the type and name of a variable, but it is not the case that we get the variable for the purpose of viewing it, but to manipulate it, which is a trivial matter for runtime. The code is as follows:


-(void) viewDidLoad {
     [super viewDidLoad];
     // Get variables
     unsigned int count;
     Ivar * mem = class_copyIvarList ([MyObject class], & count);
     // create object
     MyObject * obj = [[MyObject alloc] init];
     NSLog (@ "before runtime operate:% @", obj);
     // Setting variables
     object_setIvar (obj, mem [0], 10);
     object_setIvar (obj, mem [1], @ "isTow");
     object_setIvar (obj, mem [2], @ "isThree");
     NSLog (@ "after runtime operate:% @", obj);
    
}


TIP: When modifying an int variable, you may encounter a problem where, under arc, the compiler does not allow you to assign the value of the int type to the ID, and in buildset objective-c Automatic Reference counting is modified to No.



The printing effect is as follows:






As you can see, the variables that appear to be very safe are modified by us.


let me have a look at your method.


Variables through the runtime mechanism we can take and change the value, then we dare to try those private methods, first we add some methods in the MyObject class, we only implement, do not declare them:


@interface MyObject()
{
    @private
    NSString * privateThree;
}
@end
@implementation MyObject
- (instancetype)init
{
    self = [super init];
    if (self) {
        privateOne=1;
        [email protected]"Tow";
        [email protected]"Three";
    }
    return self;
}
-(NSString *)description{
    return [NSString stringWithFormat:@"one=%d\ntow=%@\nthree=%@\n",privateOne,privateTow,privateThree];
}
-(NSString *)method1{
    return @"method1";
}
-(NSString *)method2{
    return @"method2";
}


This way we can't call them outside, and as we do with the variables, we'll first capture these methods:


// Get all member methods
     Method * mem = class_copyMethodList ([MyObject class], & count);
     // traverse
     for (int i = 0; i <count; i ++) {
         SEL name = method_getName (mem [i]);
         NSString * method = [NSString stringWithCString: sel_getName (name) encoding: NSUTF8StringEncoding];
         NSLog (@ "% @ \ n", method);
     }


Print as follows:






Given these method names, we can call them boldly:


MyObject * obj = [[MyObject alloc]init]; NSLog (@ "%@", [obj method1]);


Tip: Here the compiler will not give us a hint of the method, be assured that the call can be bold.


Vi. dynamically adding methods to the class


This is the most powerful part of the runtime mechanism to come, imagine, if we can dynamically add methods to the class, it would be a very exciting thing, note that here is the dynamic addition, and the biggest difference in the category is that this way is the runtime to decide whether to add methods.


-(void) viewDidLoad {
     [super viewDidLoad];
     // Add a new method, the third parameter is the type of the return value v is void, i is int :: is SEL, object is @ etc
     class_addMethod ([MyObject class], @selector (method3), (IMP) logHAHA, "v");
    
     unsigned int count = 0;
     Method * mem = class_copyMethodList ([MyObject class], & count);
     for (int i = 0; i <count; i ++) {
         SEL name = method_getName (mem [i]);
         NSString * method = [NSString stringWithCString: sel_getName (name) encoding: NSUTF8StringEncoding];
         NSLog (@ "% @ \ n", method);
     }
    
     MyObject * obj = [[MyObject alloc] init];
     // run this method
     [obj method3];
    
}
// Method implementation
void logHAHA () {
     NSLog (@ "HAHA");
}


The results of the operation are as follows:






In the past the five elements can be seen, the method has been added, from the last line can be seen, the implementation of no problem.


Seven, do some small hands and feet


Programmers always get the push, now we're going to do something and replace the function in our class with our function:


-(void) viewDidLoad {
     [super viewDidLoad];
     MyObject * obj = [[MyObject alloc] init];
     // Replace the previous method
     NSLog (@ "% @", [obj method1]);
     //replace
     class_replaceMethod ([MyObject class], @selector (method1), (IMP) logHAHA, "v");
     [obj method1];
    
}
void logHAHA () {
     NSLog (@ "HAHA");
} 


Print as follows:






It's cool enough this time, and in this way we can mess up the system's functions. Of course, there are many cool ways of runtime:



ID object_copy (ID obj, size_t size)



Copy an Object






ID object_dispose (ID obj)



Releasing an Object






const char *object_getclassname (ID obj)



Gets the class name of the object



Ive



void Method_exchangeimplementations (Method m1, method m2)
Implementation of exchange two methods



Application of runtime mechanism in OBJECTIVE-C


Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.