Runtime design in iOS

This article refers to information:

juejin.im/post/58f833…

draveness.me/load

www.jianshu.com/u/2de707c93…

zhuanlan.zhihu.com/p/26379488

juejin.im/post/58f830…

segmentfault.com/a/119000000…

tech.meituan.com/2015/08/12/…

A, Runtime in all actions, all messages?

Please read: octhe smalltalkstory

After reading, you will understand why in a lot of Runtime msg_send···functions that begin with; all acts, all news is that smalltalkthe basic idea ocis precisely follows this idea.

Smalltalk is the world's second object-oriented language, the basic idea is:

  • 1, a basic idea: fully object-oriented. Everything is an object, but also thorough than Java object-oriented, including data constants are objects.

  • 2, the basic idea two: all acts (that is, the method in java), is no longer understood as a method call, but understood to be sending a message to an object, that is, a command is sent to an object, the message commands can be parameterized . The OC inventor Brad Cox and Tom Love in the mainstream and efficient C language based on the idea you want to learn Smalltalk both easy to use and come up with a lightweight C language extensions, but C and Smalltalk syntax and ideas misfits, such as Smalltalk, everything is an object, all calls are message: (original: segmentfault.com/a/119000000... )

Second, the method of calling Runtime

Please read: OC origin

Through octhe smalltalkstory, we just preliminary understanding of the strange syntax runtime, which is precisely what the "OC origin" as expressed in vague, but in the "OC origin," we can actually see more.

Dynamics of OC

OC function call is called a message is sent, the calling process is the dynamic, at compile time and can not really decide which function calls

What you call a method in Objective-C which in the end does it mean, and whether, like C ++, any non-virtual methods will be compiled into a unique symbol, while calling to find the symbol table, find this method and then call it?

the answer is negative. Call a method in Objective-C which time, runtime layer will call this translated into:

[obj makeTest]; ->objc_msgSend(obj,@selector(makeTest));

objc_msgSend方法包含两个必要参数:receiver、方法名(即:selector),如:[receiver message];将被转换为objc_msgSend(receiver, selector);

此外objc_msgSend方法也能使用message的参数,如: objc_msgSend(receiver, selector, arg1, arg2, …);

A objc_class in Runtime are defined as follows:

Quoted one iOS Runtime: Class and meta-class original

struct objc_class {
    Class isa  OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
    Class super_class                       OBJC2_UNAVAILABLE;  // 父类
    const char *name                        OBJC2_UNAVAILABLE;  // 类名
    long version                            OBJC2_UNAVAILABLE;  // 类的版本信息,默认为0
    long info                               OBJC2_UNAVAILABLE;  // 类信息,供运行期使用的一些位标识
    long instance_size                      OBJC2_UNAVAILABLE;  // 该类的实例变量大小
    struct objc_ivar_list *ivars            OBJC2_UNAVAILABLE;  // 该类的成员变量链表
    struct objc_method_list **methodLists   OBJC2_UNAVAILABLE;  // 方法定义的链表
    struct objc_cache *cache                OBJC2_UNAVAILABLE;  // 方法缓存
    struct objc_protocol_list *protocols    OBJC2_UNAVAILABLE;  // 协议链表
#endif
} OBJC2_UNAVAILABLE;
复制代码

isa: Note that in the Objective-C, all of the class itself is a target, Class this object there is also a isa pointer metaClass (metaclass)

Note: The class is an object, the object class is also another instance of the class object, Runtime, designed a meta class, to create a class object via meta class, so the class object isa points to the corresponding meta clas, we become metaclass. While the meta class is an object, all point isa metaclass metaclass root, root metaclass isa point to themselves, by this design, isa overall structure forms a closed loop.

Instance of an object, the object class, metaclass
  • Instance object: the object is instantiated our usual classes such as Obj * obj = [Obj new]; then this is an instance of an object obj

  • Class object: this time whether a bit strange, in fact, the class is an object, such as Obj is actually a class object

  • Yuan class: in fact isa class object pointed to class.

We are concerned objc_classin this structure:

struct objc_cache *cache OBJC2_UNAVAILABLE; // 方法缓存

Method for caching recently used. When a receiver object receives a message, it will look for objects to respond to this message based isa pointer. In actual use, the object is only part of the method is commonly used in many ways in fact, rarely used or do not have access. In this case, if each message, we are all methodLists traversal again, performance is bound to be poor. At this time, cache comes in handy. After every time we had to call a method, this method will be cached in the cache list, runtime when the next call will be a priority to find the cache, if the cache is not only to find methodLists method. Thus, for calling those methods often used, but to improve the efficiency of the call

Connect the text: objc_msgSendthe message distribution into the following steps:

Quote original: in-depth understanding of Objective-C: caching method

  1. Determine whether the receiver is nil, that is, the first argument self objc_msgSend, that is, that method belongs to the object to be called

  2. Looking from the cache, found the distribution

  3. If none is found, use objc-class.mm in _class_lookupMethodAndLoadCache3

    • If the support GC, GC ignored method of non-environmental (retain, etc.)
    • Looking selector from the method list to the class, if found, is filled into the cache, and returns the selector, or
    • Looking parent class method list, and turn up looking until you find selector, fill the cache, and returns the selector, or
    • Call _class_resolveMethod, if you can dynamically resolve as a selector, not the cache, the method returns, otherwise
    • Forward this selector, otherwise an error, an exception is thrown

objc_cacheIt is defined as follows:

struct objc_cache {
    uintptr_t mask;            /* total = mask + 1 */
    uintptr_t occupied;       
    cache_entry *buckets[1];
};
复制代码

objc_cacheDefinition seems very simple, it contains the following three variables:

  • 1), mask: the current can be considered to achieve the maximum index (starting from 0), the cache size (total) is the mask + 1

  • 2), occupied: the slot is occupied, because the cache is in the form of a hash table, it will be empty tank, and occupied represents the number of currently occupied

  • 3), buckets: hash table represented by an array, cache_entry type, each represents a method cache_entry buffer (buckets defined objc_cache the end of this description is a variable-length array)

And cache_entryis defined as follows:

typedef struct {
    SEL name;     // same layout as struct old_method
    void *unused;
    IMP imp;  // same layout as struct old_method
} cache_entry;
复制代码

cache_entry definition also includes three fields, namely:

  • 1), name, cached method name
  • 2), unused, reserved field, has not been used.
  • 3), imp, implemented method

After a call to understand the form and call the procedure, including the concept of caching, metaclasses, and other methods of the class object, return to OC origin , we look

The author explains the whole process is probably as follows:

  1. objc_msgSend method of operating in a certain order, to accomplish dynamic binding.
  2. objc_msgSend function to invoke the appropriate method depending on the type of receiver and selector.
  3. When the compiler performs the above conversion, corresponding to first find the class obj obj by isa pointer in objc_msgSend function.
  4. Each internal object has a default isa pointer to the class object is used, the object is hidden isa pointer to create the object's class.
  5. Searches for the corresponding function SEL to go through in the Class cache (the cache for the method SEL key list is stored by the hash table, so that the function can be improved search speed),
  6. If the cache is not found, go methodList find, if not found methodlist, then go find superClass,
  7. If found, the method is added to the cache in order to facilitate the next search, and jump to the corresponding function through a function pointer method of execution.
  8. If the method still can not find the final match, then execute "message forwarding" (message forwarding) operation.

Message forwarding process:

In-depth understanding of Objective-C Runtime original mechanism

Try to find the message in methodList object class. If found, the jump to the corresponding function to execute code that implements IMP; if not found,

  • Runtime sends + resolveInstanceMethod: or + resolveClassMethod: try to resolve the message;
  • If the resolve method returns NO, Runtime sends -forwardingTargetForSelector: allows you to forward this message to another object;
  • If no new target object is returned, Runtime will be sent -methodSignatureForSelector: and -forwardInvocation: messages. You can send -invokeWithTarget: Message to manually forward the message or send -doesNotRecognizeSelector: throw an exception

Three, Method Swizzling principle

We clearly understand that the above runtime method call, namely to achieve a principle object sends a message. OC dynamic hesitation, we can also use this feature sly. "狸猫换太子" under the IMP first understand the method mentioned above in the cache cache_entryis defined as follows:

typedef struct {
    SEL name;     // same layout as struct old_method
    void *unused;
    IMP imp;  // same layout as struct old_method
} cache_entry;
复制代码

Each class has a method list, kept the mapping between names and selector methods to achieve. Method of realization directed to a particular IMP, IMP exchange can be realized. IMP similar function pointers.

  • Method_exchangeImplementations exchange with two methods Imp;

  • Class_replaceMethod by modifying the like;

  • With method_setImplementation to set up a method of direct IMP, in the final analysis, it is the substitution of the IMP selector. Quote original OC origin an example

- (void)viewDidLoad {
[super viewDidLoad];

Method ori_Method =  class_getInstanceMethod([self class], @selector(testOne));
Method my_Method = class_getInstanceMethod([self class], @selector(testTwo));
method_exchangeImplementations(ori_Method, my_Method);

[self testOne];
}

- (void)testOne {
NSLog(@"原来的");
}

- (void)testTwo {
NSLog(@"改变了");
}
复制代码

Fourth, the use of dynamic loading of classes and methods Runtime

Create a new class at runtime, only 3 steps:

1, allocates memory for the class pair, using function objc_allocateClassPair

2, the method requires increasing class_addMethod function, instance variables increase class_addIvar

3, register this class with objc_registerClassPair function, so that it can be used by others.

- (void)ex_registerClassPair {
Class TestClass= objc_allocateClassPair([NSObject class], "TestClass", 0);
//为类添加变量
class_addIvar(TestClass, "_name", sizeof(NSString*), log2(sizeof(NSString*)), @encode(NSString*));
//为类添加方法 IMP 是函数指针  typedef id (*IMP)(id, SEL, ...);
IMP i = imp_implementationWithBlock(^(id this,id other){
    NSLog(@"%@",other);
    return @123;
});
//注册方法名为 testMethod: 的方法
SEL s = sel_registerName("testMethod:");
class_addMethod(TestClass, s, i, "i@:");
//结束类的定义
objc_registerClassPair(TestClass);

//创建对象
id t = [[TestClass alloc] init];
//KVC 动态改变 对象t 中的实例变量
[t setValue:@"测试" forKey:@"name"];
NSLog(@"%@",[t valueForKey:@"name"]);
//调用 t 对象中的 s 方法选择器对于的方法
id result = [t performSelector:s withObject:@"测试内容"];
NSLog(@"%@",result);
}

复制代码

Five, category and extension

Reference iOS Runtime (a) the application of the Runtime

This article explains some of the runtime of specific applications:

  • OC certain runtime code into the code, the underlying explore, such as the realization of the principle block
  • Interception system comes with a method call (Swizzle black magic), such as interception imageNamed:, viewDidLoad, alloc
  • Achieve the classification can also increase property
  • Automatic and automatic archiving solution archives NSCoding
  • Achieve dictionary and model of automatic conversion. (MJExtension)
  • BUG artifact repair, if BUG large frame solved by Runtime, very easy to use.

About + load program look at this, runtime can draw upon APP startup speed optimization, is precisely what the iOS Application Runtime (a) Runtime of the missing.

Of course, there is a very systematic introduction of summary runtime: Runtime introduction , we can finally see the summary, it would be difficult to understand or to stick with it.

Lack of personal ability, there have been mistakes, please correct the message area.

He reiterated reference data:

juejin.im/post/58f833…

draveness.me/load

www.jianshu.com/u/2de707c93…

zhuanlan.zhihu.com/p/26379488

juejin.im/post/58f830…

segmentfault.com/a/119000000…

tech.meituan.com/2015/08/12/…

Guess you like

Origin blog.csdn.net/weixin_34326558/article/details/91391831