The Runtime is introduced

Objective-c is a dynamic language, which means it requires not only a compiler, but also a runtime system to dynamically create classes and objects, do messaging, and forwarding. Understanding the Objective-C Runtime mechanism can help us better understand the language and, when appropriate, extend it to solve design or technical problems on a project at the system level. To understand the Runtime, you need to understand its core — Messaging.

Runtime objc_msgSend Execution process

  • Method calls in OC are converted to objc_msgSend, which sends a message to the receiver (selector method name).
  • The execution of objc_msgSend can be divided into three phases
    • Message is sent
    • Dynamic method parsing
    • forward

Ps: If none of the three phases can find a method, the classic error is reported: unrecognized selector sent to instance

Message is sent

  1. throughReceiver (message receiver)Isa pointer foundreceivertheClass
  2. inClasstheCache (method cache)In the hash table ofIMP (Method implementation)
  3. If theCache (method cache)Is not found inIMP, continue inClasstheMethodListTo find the correspondingselectorIf found, fill toCache (method cache)And returnselector;
  4. If theclassIn, this is not foundselector, just continue in itssuperClassIn theCache (method cache)If found in the cacheClassIn theCache (method cache)In the
  5. If you don’t find it, you’ll find itsuperClassIn themethodlist, and cached toClassIn theCache (method cache)In the
  6. If you still don’t find itIMP (Method implementation), and determine if there is still onesuperClassIf steps 4 and 5 are repeated, if not, the dynamic method parsing phase begins

Dynamic method parsing

If not, the developer has implemented the +resolveInstanceMethod:, resolveClassMethod: method to dynamically resolve the method. If it does, mark it as dynamically resolved. The step that goes back to the message sending process (looking for methods in the Class’s cache) begins. If it has been dynamically resolved, it will enter the next stage of message forwarding.

Example:

ZQPerson * p = [[ZQPerson alloc]init];
        [p test]; Print result: -[ZQPerson other]Copy the code
  • The Person class does not implement the test methodresolveInstanceMethodDynamically points to the implementation of the other method
person.h

@interface ZQPerson : NSObject
- (void)test;
@end

person.m

 - (void)other{
    NSLog(@"%s",__func__);
}

+ (BOOL)resolveInstanceMethod:(SEL)sel{
    Method otherMethod = class_getInstanceMethod(self, @selector(other));
    if (sel == @selector(test)) {
        class_addMethod(self, sel, method_getImplementation(otherMethod), method_getTypeEncoding(otherMethod));
        return YES;
    }
    return [super resolveInstanceMethod:sel];
}
Copy the code

forward

No concrete implementation is found during message sending or dynamic method parsing, which leads to message forwarding. Message forwarding: Forwarding a message to someone else. Will try to call (id) forwardingTargetForSelector (SEL) aSelector method returns nil value part, is called obj_msgSend (return value, SEL), If forwardingTargetForSelector returned to nil, then the to achieve methodSignatureForSelector, forwardInvocation, these two methods.

Method signature: Return value type, Parameter types - (NSMethodSignature *) methodSignatureForSelector: (SEL) aSelector {the if (aSelector = = @ the selector (test)) {return [NSMethodSignature signatureWithObjCTypes:"v@:"]; } return [super methodSignatureForSelector:aSelector]; } //NSInvocation encapsulates a method call including: // Invocation. Target // Invocation. Selector method name // [anInvocation Invocation getArgument:NULL atIndex:0]; Parameter - (void)forwardInvocation:(NSInvocation *)anInvocation{anInvocation. Target = [[ZQCat alloc]init]; // Specify the invocation to receive [anInvocation invoke]; // Invocation invokeWithTarget:[[ZQCat alloc]init]]; }Copy the code