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 disassembly
Allow assembly debuggingXcode
In themacOS
Version to10.15
Below, or the iOS version13.0
The following. Take a look at assembly codeSource code analysis:isKindOfClass
andisMemberOfClass
The underlying implementation isobjc_msgSend
Message forwarding. throughSEL
Find the correspondingIMP
Xcode
In themacOS
Version to10.15
Above, or the iOS version13.0
The above. Take a look at assembly codeSource code analysis:isKindOfClass
Underlying implementationobjc_opt_isKindOfClass
The underlying implementation of classobjc_opt_class
.isMemberOfClass
Or 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:
+isKindOfClass
Process.Class of metaclass
vsCLS (Classes to compare)
, different continue to compare.The parent of a metaclass
vscls
Continue to compare until foundA metaclass
.Root metaclass vs CLS
, different continue to compare.Root class (NSObject)
vscls
, if not the sameThe parent of the root class (NSObject)
fornil
, and returns NO-isKindOfClass
Process. Gets the currentObject class
.class
vscls
, different continue to compare.The parent of the class
vscls
Continue to compare until foundRoot class (NSObjec)
.Root class (NSObject)
vscls
If 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:
+isKindOfClass
The comparison is(NSObject metaclass)NSObject
vsNSObject
, return 1 - reg2:
+isMemberOfClass
The comparison isNSObject's metaclass root metaclass
vsNSObject
Returns zero - reg3:
+isKindOfClass
The comparison isLGPerson's metaclass NSObject
vsLGPerson
Returns zero - reg4:
+isMemberOfClass
The comparison isLGPerson's metaclass NSObject
vsLGPerson
Returns zero - reg5:
-isKindOfClass
The comparison isNSObject Indicates the object's class NSObject
vsNSObject
, return 1 - reg6:
-isMemberOfClass
The comparison isNSObject class
vsNSObject
, return 1 - reg7:
-isKindOfClass
The comparison isLGPerson The LGPerson object belongs to class LGPerson
vsLGPerson
, return 1 - reg8:
-isMemberOfClass
The comparison isLGPerson class
vsLGPerson
, 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