Let’s start with lookUpImpOrForward

  • realizeAndInitializeIfNeeded_locked jump

  • initializeAndLeaveLocked jump

  • initializeAndMaybeRelock jump

  • initializeNonMetaClass jump

  • callInitialize jump

CallInitialize makes a system call to the current class

Dichotomy search

For example, now there are 8 methods from 1 to 8, count=8, suppose the correct method is now at position 7, starting at position 0, and moving to the right

base + (count >> 1) = 0 + (8 >> 1) = 1000 >> 1 = 0100 = 4 // The current position
base = probe + 1 = 4 + 1 = 5;// The current position
base = probe + 1 = 5 + 1 = 6;// The current position
base = probe + 1 = 5 + 1 = 7;// The current position

count -- = 8 - 1 = 7;
count = 7 >> 1 = 0111 >> 1 = 0011 = 3
count = 6 >> 1 = 0011 >> 1 = 0001 = 1
count -- = 3 - 1 = 2;
count = 2 >> 1 = 0010 >> 1 = 0001 = 1
1 >> 1 = 0001 >> 1 = 0
Copy the code
  • Lookupimp ->lookupimp-> lookupimp-> lookupimp

Pit point

1. Object calling a class method can be successful, as long as it is processed in NSObject, and added in the class, the root cause is isa’s bitmap.

If you do not write the implementation in the m file, you will receive the following error

  • _objc_msgForward_impcache

  • __objc_forward_handler

// Key code
  _objc_fatal("%c[%s %s]: unrecognized selector sent to instance %p "
                "(no message forward handler is installed)", 
                class_isMetaClass(object_getClass(self))?'+' : The '-', 
                object_getClassName(self), sel_getName(sel), self);
Copy the code

Dynamic method resolution

// The singleton method is executed only once
//3 &2 = 0011&0010 = 0010 = 2
//2 & 2 = 0 = behavior
if (slowpath(behavior & LOOKUP_RESOLVER)) {
        behavior ^= LOOKUP_RESOLVER;
        return resolveMethod_locked(inst, sel, cls, behavior);
    }
Copy the code

Dynamic default assignment again

Source of behaviors

When the method is not written, cache lookup and slow recursive process lookup, still not found, resulting in a crash!! !

To give one last chance, to find lookUpImpOrForwardTryCache, returns the imp

return lookUpImpOrForwardTryCache(inst, sel, cls, behavior);


#if CONFIG_USE_PREOPT_CACHES
    if (fastpath(cls->cache.isConstantOptimizedCache(/* strict */true))) {
        imp = cache_getImp(cls->cache.preoptFallbackClass(), sel);
    }
#endif
 if (slowpath(imp == NULL)) {
        returnlookUpImpOrForward(inst, sel, cls, behavior); } try lookUpImpOrForward again if the following conditions are met// Determine whether a metaclass is a metaclass
       if (! cls->isMetaClass()) {
        // try [cls resolveInstanceMethod:sel]
        resolveInstanceMethod(inst, sel, cls);
    } 
    else {
        // try [nonMetaClass resolveClassMethod:sel]
        // and [cls resolveInstanceMethod:sel]
        resolveClassMethod(inst, sel, cls);
        if (!lookUpImpOrNilTryCache(inst, sel, cls)) {
            resolveInstanceMethod(inst, sel, cls);
        }
    }
Copy the code
  • resolveInstanceMethod jump

- resolve_sel The system sends this message and runs IMP IMP = lookUpImpOrNilTryCache(inst, sel, CLS); TryCache is executed twice hereSEL resolve_sel = @selector(resolveInstanceMethod:)
 BOOL (*msg)(Class, SEL, SEL) = (typeof(msg))objc_msgSend;
    bool resolved = msg(cls, resolve_sel, sel);
Copy the code

M Add the following code

Before the program reports an error, the method defined above is used and the output is as follows


+ (BOOL)resolveInstanceMethod:(SEL)sel{
    
    if (sel == @selector(sayNB)) {
        
        IMP teacherSayImp = class_getMethodImplementation(self.@selector(teacherSay));
        
        Method method = class_getInstanceMethod(self.@selector(teacherSay));
        
        const char *type = method_getTypeEncoding(method);
        
        return  class_addMethod(self,sel,teacherSayImp,type);
    }
    
    NSLog(@"resolveInstanceMethod : %@-%@".self.NSStringFromSelector(sel));
 
    return [super resolveInstanceMethod:sel];
    
}

 // Replace the output
 -[HLTeacher teacherSay]
Program ended with exit code: 0
Copy the code

The system is implemented by default, and the system will help you.

Dynamic resolution of class methods

 BOOL (*msg)(Class, SEL, SEL) = (typeof(msg))objc_msgSend;
 bool resolved = msg(nonmeta, @selector(resolveClassMethod:), sel);
Copy the code

Nonmeta Current metaclass

resolveClassMethod : HLTeacher-encodeWithOSLogCoder:options:maxLength:
resolveClassMethod : HLTeacher-sayHappy
+[HLTeacher sayHappy]: unrecognized selector sent to class 0x100008508
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+[HLTeacher sayHappy]: unrecognized selector sent to class 0x100008508'

Copy the code

resolveClassMethod : HLTeacher-encodeWithOSLogCoder:options:maxLength:
HLTeacher - +[HLTeacher sayHello]
Copy the code

Summary:

  • 1. OC code runs according to the method name SEL(e.g. SayHappy) and then looks for the method implementation (IMP).
  • 2. If we implement a classification method (such as the code above) and all methods are not found, we can listen to it and send a message when the method implementation is not found
  • 3, non-Apple source module method name judgment, Apple source code do not Hook, Hook is our own code
  • 4, AOP aspect oriented programming, object-oriented programming (OOP) a kind of extension, can make the coupling degree between the parts of the business logic is reduced, improve the program reusability, improve the development efficiency (extension)
  • 5, OOP object-oriented programming, object division is very clear, there will be redundant code, and then extract the public class, will cause strong dependency, strong coupling, so we should try to avoid intrusion, can be injected through the dynamic method (runtime runtime use), as a cut. A cut point is the way to cut in (e.g., sayhappy)
  • 6, the disadvantage is too much judgment, will produce performance consumption

To be continued……