A list,

OC is a dynamic language, and Runtime is a core technology for developing iOS applications using OC. Many dynamic features in OC are implemented through the Runtime.

When a class calls a method, it uses the Message mechanism of the Runtime to send a message to achieve the purpose of calling the method. The underlying function is called objc_msgSend.

If you want to send a message to an object, there are at most three phases: message sending, dynamic method parsing, and message forwarding. If the message is not found through all three phases, the program throws an error at runtime: unrecognized Selector sent to instance.

2. Message sending

  1. When we send a message to an object, we find the object’s class object through the object’s ISA. Looks for the method in the method cache of the class object and calls it if it does.

  2. If the method does not exist in the class object’s cache, it looks for the method where the class object stores the method. If it exists, it is added to the class object’s method cache first, and then it is called.

  3. If not found, the method through the superclass pointer to its parent class, first find the superclass method in the cache to have the method, if there is then call this method, if there is no the way in the cache, then the parent class of methods for searching the method in the list, if found, this method first cache to the methods of class object in the cache, and then to call

  4. If the parent of the metaclass object still does not find the method, find the parent and repeat step 3. If the method is not eventually found, the second stage is dynamic method resolution.

Dynamic method analysis

When the message sending phase is complete and no corresponding method is found, the dynamic method resolution phase occurs. Dynamic method resolution can help us intercept methods that are not implemented during the message sending phase. Use runtime to dynamically add a method to the method provided by dynamic method resolution. Call our dynamically added method when the method called in the message sending phase is not found.

The following uses the instance method as an example:

We define a class in which only methods are declared but not implemented.

@interface SomeClass : NSObject

- (void)foo;

@end
Copy the code

Since it is an instance method, we need to override the resolveInstanceMethod method in the SomeClass implementation file to implement dynamic method resolution in this method.

Let’s say that when we call foo, because foo is not implemented, and we go to the dynamic method resolution phase, we let it call the implementation of bar.

- (void)bar { NSLog(@"%s", __func__); } + (BOOL)resolveInstanceMethod:(SEL) SEL {// determine if the Method name is foo if (SEL == @selector(foo)) {// get the added Method Method = class_getInstanceMethod(self, @selector(bar)); // IMP IMP = class_getMethodImplementation(self, @selector(bar)); IMP imp = method_getImplementation(method); // Get TypeEncoding const char *types = method_getTypeEncoding(method); Class_addMethod (self, sel, imp, types); return YES; } return [super resolveInstanceMethod:sel]; }Copy the code
  • using runtimeclass_addMethoD function dynamic addition method
    • First argument: pass in the class object if the instance method is added, or the metaclass object if the class method is added
    • Second parameter: the method name of the dynamically added method
    • Parameter 3: the method implementation of the dynamically added method is the function address
    • Parameter 4: dynamically added method parameters and return valuestypeEncoding

After the method is added in the dynamic resolution phase, the process of sending the message is repeated.

If dynamic method resolution is not implemented, then the third phase of message forwarding is reached

4. Message forwarding

No corresponding message can be found in the current two stages, and the message forwarding stage will finally come. We still use the example method to illustrate:

  • It first calls- (id)forwardingTargetForSelector:(SEL)aSelectorMethod in which the message is forwarded to other classes for processing.
- (id)forwardingTargetForSelector:(SEL)aSelector {
    if (aSelector == @selector(foo)) {
        return [[OtherClass alloc] init];
    }
    return [super forwardingTargetForSelector:aSelector];
}

// OtherClass
@interface OtherClass : NSObject

- (void)foo;

@end
  
@implementation OtherClass
- (void)foo {
    NSLog(@"%s", __func__);
}
@end
Copy the code
  • To create aOtherClassClass, which is declared and implementedfoomethods
  • forwardingTargetForSelector MethodOtherClassThat means we will pass the message toOtherClassThe class is calledfooMethods.

If forwardingTargetForSelector method returns nil or not at all, message forwarding phase will call other methods for processing.

  • The first thing I call ismethodSignatureForSelectorMethod, which returns aNSMethodSignatureObject if the return value is notnil, then he will callforwardInvocationMethod, and pass in aNSInvocationObject that encapsulates the conditions necessary for a method call.
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { if (aSelector == @selector(foo)) { Method method = class_getInstanceMethod([OtherClass class], aSelector); const char *types = method_getTypeEncoding(method); NSMethodSignature *signature = [NSMethodSignature signatureWithObjCTypes:types]; return signature; } return [super methodSignatureForSelector:aSelector]; } - (void)forwardInvocation:(NSInvocation *)anInvocation { [anInvocation invokeWithTarget:[[OtherClass alloc] init]]; // If the types are random, the anInvocation is meaningless. OtherClass *oc = [[OtherClass alloc] init]; [oc bar]; }Copy the code
  • If we want to useanInvocationTo process messages, so inmethodSignatureForSelectorIn the methodtypesMake sure you get it right, abouttypesHow can we look at apple’s official documentationType Encoding.
  • If we don’t want to useanInvocationProcessing messages,typesIn fact, it can be uploaded, so we can’t use itanInvocationIt’s time to process the message, because it encapsulates all sorts of crap.