The interview questions

Without further ado, explore isKindOfClass and isMemberOfClass through an interview question

  BOOL re1 = [(id)[NSObject class] isKindOfClass:[NSObject class]];       //
    BOOL re2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]];     //
    BOOL re3 = [(id)[LGPerson class] isKindOfClass:[LGPerson class]];       //
    BOOL re4 = [(id)[LGPerson class] isMemberOfClass:[LGPerson class]];     //
    NSLog(@" re1 :%hhd\n re2 :%hhd\n re3 :%hhd\n re4 :%hhd\n",re1,re2,re3,re4);

    BOOL re5 = [(id)[NSObject alloc] isKindOfClass:[NSObject class]];       //
    BOOL re6 = [(id)[NSObject alloc] isMemberOfClass:[NSObject class]];     //
    BOOL re7 = [(id)[LGPerson alloc] isKindOfClass:[LGPerson class]];       //
    BOOL re8 = [(id)[LGPerson alloc] isMemberOfClass:[LGPerson class]];     //
    NSLog(@" re5 :%hhd\n re6 :%hhd\n re7 :%hhd\n re8 :%hhd\n",re5,re6,re7,re8);

Copy the code

What is the result of running this code

The results of

2021-07-09 16:22:06.480627+0800 KCObjcBuild[74708:6582366] RE1:1 RE2:0 RE3:0 RE4:0 2021-07-09 16:22:06.481524+0800 KCObjcBuild[74708:6582366] re5 :1 re6 :1 re7 :1 re8 :1Copy the code

Analysis of the

Why is it that it turns out that way? Open it updebug->debug workflow->always show disassemblyAllow assembly debugging

XcodeIn themacOSVersion to10.15Below, or the iOS version13.0The following. Take a look at assembly codeSource code analysis:isKindOfClassandisMemberOfClassThe underlying implementation isobjc_msgSendMessage forwarding. throughSELFind the correspondingIMP

XcodeIn themacOSVersion to10.15Above, or the iOS version13.0The above. Take a look at assembly codeSource code analysis:isKindOfClassUnderlying implementationobjc_opt_isKindOfClassThe underlying implementation of classobjc_opt_class.isMemberOfClassOr forward the message

IsKindOfClass underlying implementation

BOOL isKindOfClass:(Class) CLS {// TCLS = self->ISA() for (Class TCLS = self->ISA(); tcls; TCLS = TCLS ->getSuperclass()) {if (TCLS == CLS) return YES; } return NO; } - (BOOL)isKindOfClass:(Class) CLS {// TCLS = Class for (Class TCLS = [self Class]; tcls; TCLS = TCLS ->getSuperclass()) {if (TCLS == CLS) return YES; } return NO; }Copy the code

Analysis:

  • +isKindOfClassProcess.Class of metaclass vs CLS (Classes to compare), different continue to compare.The parent of a metaclass vs clsContinue to compare until foundA metaclass.Root metaclass vs CLS, different continue to compare.Root class (NSObject) vs cls, if not the sameThe parent of the root class (NSObject)fornil, and returns NO
  • -isKindOfClassProcess. Gets the currentObject class.class vs cls, different continue to compare.The parent of the class vs clsContinue to compare until foundRoot class (NSObjec).Root class (NSObject) vs clsIf not, the root class(NSObject)fornil, and returns NO

IsMemberOfClass underlying implementation

BOOL isMemberOfClass:(Class) CLS {return self->ISA() == CLS; } - (BOOL)isMemberOfClass:(Class) CLS {return [self Class] == CLS; }Copy the code

Analysis:

  • + isMemberOfClass process. Class metaclass vs CLS (the class to compare), return YES if the same, otherwise return NO

  • – isMemberOfClass process. Class vs CLS, return YES if they are the same, or NO if they are not

Objc_opt_isKindOfClass underlying implementation

Objc_opt_isKindOfClass (ID _Nullable obj, Class _Nullable CLS) OBJC_AVAILABLE(10.15, 13.0, 13.0, 6.0, 5.0); // Calls [obj isKindOfClass] BOOL objc_opt_isKindOfClass(id obj, Class otherClass) {#if __OBJC2__ // now use OBJC2 version // slowPath (! Obj) if obj is empty, the low probability event will not occur. obj)) return NO; Class CLS = obj->getIsa(); //fastpath(! CLS ->hasCustomCore()) (class or parent has no default isKindOfClass method) if (fastPath (! cls->hasCustomCore())) { for (Class tcls = cls; tcls; tcls = tcls->getSuperclass()) { if (tcls == otherClass) return YES; } return NO; Return ((BOOL(*)(id, SEL, Class))objc_msgSend)(obj, @selector(isKindOfClass:), otherClass); }Copy the code

Obj ->getIsa() gets the class or metaclass: obj gets the class if it’s an object, obj gets the metaclass if it’s a class, and then the for loop goes through the same code as isKindOfClass logic

Objc_opt_Class underlying implementation

OBJC_EXPORT Class _Nullable objC_opt_class (ID _Nullable obj) OBJC_AVAILABLE(10.15, 13.0, 13.0, 6.0, 5.0); // Calls [obj class] Class objc_opt_class(id obj) { #if __OBJC2__ if (slowpath(! obj)) return nil; Class CLS = obj->getIsa(); // if (fastPath (! CLS ->hasCustomCore())) {CLS ->hasCustomCore())) {CLS ->isMetaClass(); obj : cls; } #endif return ((Class(*)(id, SEL))objc_msgSend)(obj, @selector(class)); }Copy the code

Objc_opt_class returns the class if the parameter is an object, and returns the class if it is a class

The verification results

  • reg1:+isKindOfClassThe comparison is(NSObject metaclass)NSObject vs NSObject, return 1
  • reg2:+isMemberOfClassThe comparison isNSObject's metaclass root metaclass vs NSObjectReturns zero
  • reg3:+isKindOfClassThe comparison isLGPerson's metaclass NSObject vs LGPersonReturns zero
  • reg4: +isMemberOfClassThe comparison isLGPerson's metaclass NSObject vs LGPersonReturns zero
  • reg5: -isKindOfClassThe comparison isNSObject Indicates the object's class NSObject vs NSObject, return 1
  • reg6: -isMemberOfClassThe comparison isNSObject class vs NSObject, return 1
  • reg7: -isKindOfClassThe comparison isLGPerson The LGPerson object belongs to class LGPerson vs LGPerson, return 1
  • reg8: -isMemberOfClassThe comparison isLGPerson class vs LGPerson, return 1

conclusion

  • + isKindOfClass method: metaclass –> parent of metaclass –> until the root metaclass is found to compare with CLS separately

  • -iskindofClass method: class –> parent class of class –> until the root class (NSObject) is found and compared to CLS separately

  • + isMemberOfClass method: metaclass vs CLS

  • – isMemberOfClass method: class vs CLS