Summarize the use of runtime in iOS

  • 2020-06-15 10:20:18
  • OfStack

Anyone who does iOS knows or has heard of runtime, which is a lot like java's reflection, but far more than java's. runtime allows you to dynamically add properties, member variables, methods, and read/write access to a class.

1. runtime profile

RunTime stands for runtime. OC is the runtime mechanism, or one of the mechanisms at runtime, the most important of which is the messaging mechanism.

For the C language, function calls determine which function to call at compile time.

For OC functions, it is a dynamic call process, which does not determine which function is actually called at compile time, and only the function name is used when it is actually run

Find the corresponding function to call.

Facts show:

At compile time, OC can call any function, even if it is not implemented, as long as it is declared and no error is reported.

At compile time, the C language calls unimplemented functions and reports an error.

2. runtime role

Send a message

The essence of a method call is to have an object send a message.

objc_msgSend, Only objects can send messages, so begin with objc.

To use the message mechanism prerequisite, you must import #import <objc/message.h>

The message mechanism is simple to use

Message mechanism principle: The object looks up the corresponding method implementation in the mapping table according to the method number SEL


   //  create person object 
  Person *p = [[Person alloc] init];

  //  Calling object methods 
  [p eat];
  // SEL: Approach number , According to the method number, you can find the corresponding method implementation 
  [p performSelector:@selector(eat)];

  //  Essence: Let an object send a message 
  objc_msgSend(p, @selector(eat));

  //  There are two ways to call a class method 
  //  The first 1 The class calls the essence class name into the class object by the class name 
  [Person eat];
  //  The first 2 The species is called through the class object 
  [[Person class] eat];

  [personClass performSelector:@selector(eat)];
  //  When a class method is called with a class name, the underlying class name is automatically converted into a class object call 
  //  Essence: Lets a class object send a message 
  objc_msgSend([Person class], @selector(eat));

2. Exchange methods

Development and use scenarios: the system's own methods are not enough, extend some functions to the system's own methods, and keep the original functions.

Method 1: Inherit the class of the system, override the method.

Method 2: Use runtime, swap method.


@implementation ViewController


- (void)viewDidLoad {
  [super viewDidLoad];
  // Do any additional setup after loading the view, typically from a nib.
  //  Requirements: imageNamed Method provides a function to determine whether the image was successfully loaded each time it was loaded. 
  //  steps 1 : First make a classification, definition 1 A method that can load images and print them + (UIImage *)xmg_imageNamed:(NSString *)imageName;
  //  steps 2 Exchange: imageNamed and xmg_imageNamed I can call xmg_imageNamed , indirect call xmg_imageNamed The implementation of the. 
  UIImage *image = [UIImage imageNamed:@"123"];

     imageNamed:
    Implementation method : The underlying call PH_imageNamed

    nature : Swap the implementations of the two methods imageNamed and PH_imageNamed methods 
    call imageNamed It's just calling PH_imageNamed


   imageNamed Loading pictures , We don't know if the image loaded successfully 
    After the call imageNamed when , I know if the image is loaded 


}

@end


@implementation UIImage (Image)
//  Called when loading classes into memory 
+ (void)load
{
  //  Exchange method implementation , Methods are defined in classes 
  // class_getMethodImplementation: Acquisition method implementation 
  // class_getInstanceMethod: Access to the object 
  // class_getClassMethod: Get class method 
  // IMP: Method implementation 

  // imageNamed
  // Class: Which class method to get 
  // SEL: Get method number , According to the SEL You can go to the corresponding class and find the method 

  Method imageNameMethod = class_getClassMethod([UIImage class], @selector(imageNamed:));

  Method PH_imageNameMethod = class_getClassMethod([UIImage class], @selector(PH_imageNamed:));

  //  Exchange method implementation 
  method_exchangeImplementations(imageNameMethod, PH_imageNameMethod);
}

 

}

//  The system method cannot be overridden in a classification imageNamed , because the function of the system will be overwritten, and can not be called in the classification super.

//  It can load pictures and print them 
+ (UIImage *)PH_imageNamed:(NSString *)imageName
{
  //  Loading pictures 
  UIImage *image = [UIImage PH_imageNamed:imageName];
  // 2. Judgment function 
  if (image == nil) {
    NSLog(@" Loading is empty ");
  }

  return image;
}


@end

3. Add methods dynamically

Development usage scenario: If one class method is too many and it is expensive to load the class into memory, and a mapping table needs to be generated for each method, it can be solved by adding methods to a class dynamically.

Simple to use


@implementation ViewController

- (void)viewDidLoad {
  [super viewDidLoad];
  // Do any additional setup after loading the view, typically from a nib.

  Person *p = [[Person alloc] init];

  //  The default person , has not been implemented eat Method, can pass performSelector Call, but an error will be reported. 
  //  Adding a method dynamically does not report an error 
  [p performSelector:@selector(eat)];

}


@end

@implementation Person
// void(*)()
//  The default method has two implicit arguments, 
 The default 1 Each method takes two arguments ,self,_cmd, Implicit parameter 
 self: Method caller 
 _cmd: The number of the calling method 
void eat(id self,SEL sel)
{
  NSLog(@"%@ %@",self,NSStringFromSelector(sel));
}

//  when 1 An object that calls an unimplemented method will call this method handler , And it will pass the corresponding list of methods .
//  It's a good way to determine if an unimplemented method is the one we want to add dynamically 

<!-- Dynamic addition method , So let's first implement this resolveInstanceMethod-->
<!-- resolveInstanceMethod call : When a method is called that has no implementation is called resolveInstanceMethod-->
<!-- resolveInstanceMethod role : You know which methods are not implemented , The method is added dynamically -->
<!-- sel: No implementation method -->
+ (BOOL)resolveInstanceMethod:(SEL)sel
{

  if (sel == @selector(eat)) {
    //  Dynamically add eat methods 

    //  The first 1 Parameter: which class to add a method to 
    //  The first 2 Parameter: the method number of the added method 
    //  The first 3 Parameter: add method function implementation (function address) 
    //  The first 4 Parameters: Type of function, ( The return value + The parameter types ) v:void @: object ->self : said SEL->_cmd
    class_addMethod(self, @selector(eat), eat, "v@:");

  }

  return [super resolveInstanceMethod:sel];
}
@end

4. Add attributes to categories

Principle: To declare a property to a class is essentially to add an association to the class, not to add the memory space of the value directly to the class memory space.


@implementation ViewController

- (void)viewDidLoad {
  [super viewDidLoad];
  // Do any additional setup after loading the view, typically from a nib.

  //  To the system NSObject Class adds properties dynamically name

  NSObject *objc = [[NSObject alloc] init];
  objc.name = @"abc";
  NSLog(@"%@",objc.name);
}
@end


//  Associative key
static const char *key = "name";

- (void)setName:(NSString *)name
{
  //  Add attributes , With the object 
  //  To associate with an object , Add attributes 
  // object: Which object to add a property to 
  // key: The property name , According to the key To get the associated object  ,void * == id
  // value: The value of the associated 
  // policy: strategy 

  objc_setAssociatedObject(self, @"name", name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSString *)name
{

  return objc_getAssociatedObject(self, @"name");
}

The above is the usage summary of runtime in iOS. This article mainly summarizes the principle and usage. runtime has a very powerful function and needs more study and research from friends. I hope this article is helpful to you.


Related articles: