# iOS Runtime from Initial Knowledge to Practice

Keywords: iOS JSON Attribute xcode

xcode.png

** This article is suitable for readers who have not uncovered the mysterious veil of runtime. When God sees the words here, he also hopes to throw some ink at his younger brother and increase his knowledge! **

Introduction to Runtime:

It is a runtime library, basically written in C and assembly. Some work can be deferred from compilation to runtime processing, that is to say, the runtime system executes compiled code. Because of its dynamic nature, we can add, modify and match classes when the program runs.

First acquaintance with Runtime:

The objects or classes we create are structured in runtime and can be found in the header file of runtime.

#if !OBJC_TYPES_DEFINED

/// An opaque type that represents a method in a class definition.
typedef struct objc_method *Method; // Describe a method

/// An opaque type that represents an instance variable.
typedef struct objc_ivar *Ivar; // Instance variables

/// An opaque type that represents a category.
typedef struct objc_category *Category; // classification

/// An opaque type that represents an Objective-C declared property.
typedef struct objc_property *objc_property_t; // Class attribute

struct objc_class {
    Class isa  OBJC_ISA_AVAILABILITY; //Pointer, pointer of instance to class object object object object, pointer of class object to metaclass

#if !__OBJC2__
    Class super_class //Point to the parent class OBJC2_UNAVAILABLE;
    const char *name      //Class name OBJC2_UNAVAILABLE;
    long version           //Class version information OBJC2_UNAVAILABLE;
    long info                   // Class information OBJC2_UNAVAILABLE;
    long instance_size                //The size of the instance variable OBJC2_UNAVAILABLE;
    struct objc_ivar_list *ivars        //Member variable list OBJC2_UNAVAILABLE;
    struct objc_method_list **methodLists     //Method list OBJC2_UNAVAILABLE;
    struct objc_cache *cache            //Cache list (for the method that has been called, it will be stored in it, the next call will be preferred from the cache) OBJC2_UNAVAILABLE;
    struct objc_protocol_list *protocols       //Protocol list OBJC2_UNAVAILABLE;
#endif

} OBJC2_UNAVAILABLE;

Believe it if I ask you why category can't add attributes? (It can't write member variables in. h, but it can write attributes, but it crash when it calls.) You should know that, but it can be implemented indirectly in other ways, and the details will be written in a minute as **

Runtime effect

1. Send messages

Method call is to let the object send a message, which is converted to objc_msgSend at runtime. The message mechanism must be # import < objc/message.h>.
Principle of Message Mechanisms: Implementation of Object Finding Corresponding Method Based on Method Number SEL Demapping Table

Cat *cat = [Cat new];
// Direct call
[self eatFish];

// Runtime converts to
objc_msgSend(cat, @selector(eatFish));

2. Dynamic addition method

When we call [cat performance selector:@selector (play)], the program will carsh, because there is no implementation of the play method, what to do? It can be solved by the following way



@implementation Cat

void c_play(id self,SEL sel) // If you don't write self and _cmd in parentheses, you implicitly add self as method caller _cmd as method number
{
  NSLog(@"Play yourself");
}
 
//When the message receiver fails to find the corresponding method, it calls the method first, and we intercept the implementation method.
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
 
  if (sel == @selector(play)) {
     //Here we add the play method
    // Parametric 1: Which class adds method 2: Method number 3: Function address implemented by method 4: Function type
    //Function Type Interpretation: v stands for void without return value, @: stands for object, @ stands for SEL
    class_addMethod(self, @selector(play), c_play, "v@:");
 
  }
 
  return [super resolveInstanceMethod:sel];
}
@end

In this way, when we call the [cat performance Selector:@selector (play)] program, we won't crash because we've added it dynamically; if we add the class method resolveClassMethod, it's the same.

3. Exchange of methods

** If there is such a requirement, I don't think the function of the system is very useful. If I can't change the system method, I add some functions to this method. For example, I don't crash the nil even when I insert it into the array. I use imageNamed: This method to know whether the image has been loaded successfully or not.

You might think of inheriting or rewriting this method (but super cannot be invoked in classification, rewriting overrides previous functions). Let's try runtime.

@implementation UIImage (Image)
// A method called early in memory for categorization, in which the exchange of methods is usually implemented.
+ (void)load
{
 // Get the class method imageNamed:
  Method m1 = class_getClassMethod([UIImage class], @selector(imageNamed:));
 // //Get the class method rt_imageNamed:
  Method m2 = class_getClassMethod([UIImage class], @selector(rt_imageNamed:));
 
  // Implementation of Exchange Method
  method_exchangeImplementations(m1, m2);
}
 
// Method Implementation of Need Exchange
+ (UIImage *)rt_imageNamed:(NSString *)imageName
{
  // Perhaps the reader will ask, is this not a dead cycle, no, we have exchanged methods in the load to achieve oh, so it seems to call themselves only.
  UIImage *image = [UIImage rt_imageNamed:imageName];
  //function
  if (image == nil) {
    // do something
  }
 
  return image;
}

@end

4. Adding attributes

We said before how to add attributes to category in disguise. The answer is objc_get Associated Object, which is also a commonly used function, namely association.
It is worth noting that the associated object does not add attributes or member variables to the class\ object (because it cannot be obtained through ivarList or propertyList after setting the association, as we will practice later on)
Use scenarios: For example, add a name attribute to NSArray, which we don't need to inherit here


@interface NSArray (TestAssociated)

@property (nonatomic, copy)NSString *name;
@end
#import "NSArray+TestAssociated.h"

@implementation NSArray (TestAssociated)

static char associatedKey;

- (void)setName:(NSString *)name{

//Parameter 1: To whom to add an association 2: an associated key (to get the associated object through the key). 3: an associated object 4: an association policy (just look at the point)
    objc_setAssociatedObject(self, &associatedKey, name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}

- (NSString *)name{

// Ditto
    return objc_getAssociatedObject(self, &associatedKey);
}
@end

So we can not only use the tag value, but use it like that.

NSArray *arr = @[];
    arr.name = @"111";
    
    NSLog(@"%@", arr.name);//Print value 111

5. Attributes of Printed Objects, etc.

unsigned int i = 0;
    // Print the properties of the current object
    objc_property_t *pros = class_copyPropertyList([self class], &i);
    
    for (int j = 0; j < i; j++) {
        
        NSString *name = @(property_getName(pros[j]));
        NSLog(@":%@", name);
           
    }

// Similarly, we can print more things from scratch.
objc_ivar_list //List of member variables
objc_method_list //Method list
...

If you see it here, you must suddenly realize that the original json conversion model written by the gods is such a realization!

Use summary: object_is usually used as the starting point for manipulating objects

The methods that operate on classes generally start with class_

Methods that operate on methods of classes or objects generally begin with method_

The method of manipulating member variables generally starts with ivar_

The way attributes are manipulated generally starts with property_

The way to operate on a protocol generally starts with protocol_

Summary: There's more about runtime. I've only introduced the tip of the iceberg, or helped you to see the outline. We rarely use it in practical projects, but when we implement powerful functions, we often can't do without it, such as: json switching the model function, calling private functions and bypassing Apple audits, etc.

Posted by seriousdamage on Sat, 26 Jan 2019 11:54:15 -0800