Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.

Let’s first look at the resolveClassMethod method of a class object in method dynamic resolution.

static void resolveClassMethod(id inst, SEL sel, Class cls) { runtimeLock.assertUnlocked(); ASSERT(cls->isRealized()); ASSERT(cls->isMetaClass()); if (! lookUpImpOrNilTryCache(inst, @selector(resolveClassMethod:), cls)) { return; } Class nonmeta; { mutex_locker_t lock(runtimeLock); nonmeta = getMaybeUnrealizedNonMetaClass(cls, inst); if (! nonmeta->isRealized()) { _objc_fatal("nonmeta class %s (%p) unexpectedly not realized", nonmeta->nameForLogging(), nonmeta); } } BOOL (*msg)(Class, SEL, SEL) = (typeof(msg))objc_msgSend; bool resolved = msg(nonmeta, @selector(resolveClassMethod:), sel); IMP imp = lookUpImpOrNilTryCache(inst, sel, cls); }Copy the code
  • The arguments:
    • instClass object:
    • sel: Class method not found
    • cls: metaclass
  • calllookUpImpOrNilTryCacheFunction, internal call_lookUpImpTryCacheFunction to the current class objectresolveClassMethodMethod for slow message lookup
    • In NSObject, this method is implemented by default
    • Class objects that inherit from NSObject are not intercepted by return
  • callgetMaybeUnrealizedNonMetalClassFunction that verifies the relationship between the current class object and the metaclass and returns a normal class
  • The system USESobjc_msgSend, sendresolveClassMethodThe message
    • The message receiver is a class object
    • In the message bodySELforresolveClassMethod
    • Argument is a class method that could not be found
  • calllookUpImpOrNilTryCacheFunction to perform a slow message lookup on a class method that was not previously found
    • If theresolveInstanceMethodSuccessful processing, return the imp after processing
    • If no method is found, return_objc_msgForward_impcacheFunction address to enter the message forwarding process

Find getMaybeUnrealizedNonMetaClass function definition

static Class getMaybeUnrealizedNonMetaClass(Class metacls, id inst) { static int total, named, secondary, sharedcache, dyld3; runtimeLock.assertLocked(); ASSERT(metacls->isRealized()); total++; if (! metacls->isMetaClass()) return metacls; if (metacls->ISA() == metacls) { Class cls = metacls->getSuperclass(); ASSERT(cls->isRealized()); ASSERT(! cls->isMetaClass()); ASSERT(cls->ISA() == metacls); if (cls->ISA() == metacls) return cls; } if (inst) { Class cls = remapClass((Class)inst); while (cls) { if (cls->ISA() == metacls) { ASSERT(! cls->isMetaClassMaybeUnrealized()); return cls; } cls = cls->getSuperclass(); } #if DEBUG _objc_fatal("cls is not an instance of metacls"); #else // release build: be forgiving and fall through to slow lookups #endif } ... }Copy the code
  • Determine the CLS, if not metaclass, and return it directly
  • If CLS isa metaclass and isa points to itself, prove that the current CLS is the root metaclass, get its parent NSObject and return
  • Iterate through the current class and its parent to find the class to which ISA points to the metaclass
  • If both are found,DEBUGIn mode, error message: the current class object is not an instance of the metaclass
  • ReleaseIn mode, follow the following process to find the class object of the metaclass
    • Check whether a metaclass has a pointer to its non-metaclass
    • By metaclassmangledNameFind the class object and return it if it exists and ISA points to a metaclass
    • Look for class objects in the global Map and return them if they exist
    • In dyldclosure tableFind the class object in, return it if it exists
    • Look for class objects in the shared cache and return them if they exist
    • None of the above processes was found, error message: there is no class pointing to this metaclass

Example in lgPerson.h, declare the sayNB class method

#import <Foundation/Foundation.h>

@interface LGPerson : NSObject 

+(void)sayNB; 

@end
Copy the code

In lgPerson. m, say666 instance method and resolveInstanceMethod class method are implemented, but sayNB instance method is not implemented

#import "lgPerson. h" #import <objc/runtime.h> @implementation LGPerson -(void)say666{NSLog(@" instantiation-say666 "); } + (BOOL)resolveClassMethod:(SEL) SEL {if(SEL ==@selector(sayNB)){NSLog(@"resolveClassMethod: %@, %@", self, NSStringFromSelector(sel)); IMP imp = class_getMethodImplementation(self, @selector(say666)); Method methodSay666 = class_getInstanceMethod(self, @selector(say666)); const char *type = method_getTypeEncoding(methodSay666); const char * c = NSStringFromClass(self).UTF8String; return class_addMethod(objc_getMetaClass(c), @selector(sayNB), imp, type); } return [super resolveClassMethod:sel]; } @endCopy the code
  • If the class method called issayNB, dynamic addsayNBMethod, and populate imp withsay666Function address of
  • Due to the need to addsayNBIs a class method, so it needs to be added in the metaclass

In the main function, call the sayNB class method of LGPerson

int main(int argc, const char * argv[]) { @autoreleasepool { [LGPerson sayNB]; } return 0; } ------------------------- // Output: example method -say666Copy the code
  • Automatically entered intoresolveClassMethodmethods