The problem

Given WLWPerson: NSObject, what is the following print

    BOOL re1 = [(id)[NSObject class] isKindOfClass: [NSObject class]];       //
    BOOL re2 = [(id) [NSObject class] isMemberOfClass: [NSObject class]];     //
    BOOL re3 = [(id) [WLWPerson class] isKindOfClass: [WLWPerson class]];       //
    BOOL re4 = [(id) [WLWPerson class] isMemberOfClass: [WLWPerson 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) [WLWPerson alloc] isKindOfClass: [WLWPerson class]];       //
    BOOL re8 = [(id) [WLWPerson alloc] isMemberOfClass: [WLWPerson class]];     //
    NSLog(@" re5: %hhd\n re6: %hhd\n re7: %hhd\n re8: %hhd\n",re5.re6.re7.re8);
Copy the code

Print the result

2021-07-06 15:49:48.316771+0800 KCObjcBuild[16324:1396474] RE1:1 RE2:0 RE3:0 RE4:0 2021-07-06 15:49:48.319309+0800 KCObjcBuild[16324:1396474] re5 :1 re6 :1 re7 :1 re8 :1Copy the code

Inheritance and ISA Flowchart (emphasis)

IsKindOfClass analysis

The function that is called

To figure this out, we first need to know what isKindOfClass’s underlying function is called. This can be seen in assembly, not in the source code, because LLVM may be doing middle-level processing on it at compile time, like calling + alloc, The actual first call is objc_alloc

It can be seen thatisKindOfClassWhat’s actually called isobjc_opt_isKindOfClass

  • To viewllvmSource code discovery, a priority call table,the table of ObjC "accelerated dispatch" functions

  • Because these methods are rarely overridden, the compiler replaces the callsobjc_msgSendFunction this checks if the method is overridden and calls the function directly

Logic of judgment

  • Find out what the logic is and find the function in the source codeobjc_opt_isKindOfClass

  • Comments also indicate the callisKindOfClassGo here
  • Must be__OBJC2__This is where the most recent versions go
  • Class cls = obj->getIsa()
    • Obj is an instance object, such as:[NSObject alloc]It returns theclass
    • Obj isclass, such as:[NSObjct Class], returns the metaclass
  • fastpath(! cls->hasCustomCore()) = true

Whether there is a defaultnew/self/class/respondsToSelector/isKindOfWe all know about inheritanceNSObjectThere’s got to be one of these ways, so it’s better to do it twicetrue

  • Class tcls = cls; tcls; tcls = tcls->getSuperclass()And getThe parent class
  • tcls == otherClassself.classandself.superClaeeCompared with, untilnilHave the same istrueThere is no vice versa
  • ((BOOL(*)(id, SEL, Class))objc_msgSend)(obj, @selector(isKindOfClass:), otherClass)If the above logic is not followed, it will passobjc_msgSendSend a message, callisKindOfClassBut the current version doesn’t go that far

conclusion

  • If it is an instance object, it is compared with its own class or its parent class
  • If it is a class, it is compared with a metaclass or a parent of a metaclass

parsing

 BOOL re1 = [(id)[NSObject class] isKindOfClass:[NSObject class]]; 
Copy the code
  • [NSObject class]The root classSo takeThe root metaclass or the parent of the root metaclasswithThe root classTo compare
  • The parent of the root metaclassThe root class, sorel1 = 1
 BOOL re3 = [(id)[WLWPerson class] isKindOfClass:[WLWPerson class]];
Copy the code
  • [WLWPerson class]WLWPerson classSo takeMetaWLWPersonorMetaWLWPersonThe parent of the andWLWPerson classTo compare
  • First of all,MetaWLWPerson ! = WLWPerson
  • MetaWLWPerson parent classMetaNSObject.MetaNSObject ! = WLWPerson
  • MetaNSObjectIs the parent classNSObject.NSObject ! = WLWPerson, sore3 = 0
 BOOL re5 = [(id)[NSObject alloc] isKindOfClass:[NSObject class]];
Copy the code
  • [NSObject alloc]It’s an instance object, so it’s a fetchNSObjectorNSObjectThe parent of the andNSObjectTo compare
  • clearlyNSObject = NSObject, sore5 = 1
BOOL re7 = [(id)[WLWPerson alloc] isKindOfClass:[WLWPerson class]];
Copy the code
  • [WLWPerson alloc]It’s an instance object, so it’s a fetchWLWPersonWLWPersonThe parent of the andNSObjectTo compare
  • WLWPersonIs the parent classNSObject.NSObject = NSObject, sore7 = 1

IsMemberOfClass analysis

The underlying method called

  • If it’s a class method, take itself -> ISA()That isThe metaclassInstead of comparing
  • Instance methods[self class]That is, the class of the object compared to it

parsing

BOOL re2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]];
Copy the code
  • [NSObject class]Call the class method, so take the root metaclassMeataRootNSObjectWith the root classNSObjectTo compare
  • clearlyMeataRootNSObject ! = NSObject, sore2 = 0
BOOL re4 = [(id)[WLWPerson class] isMemberOfClass:[WLWPerson class]]; 
Copy the code
  • [WLWPerson class]Call the class method, soMetaWLWPersonWLWPersonTo compare
  • MetaWLWPerson ! = WLWPerson, sore4 = 0
BOOL re6 = [(id)[NSObject alloc] isMemberOfClass:[NSObject class]];
 
BOOL re8 = [(id)[WLWPerson alloc] isMemberOfClass:[WLWPerson class]];
Copy the code
  • They’re both calling instance methods, so they’re comparing the object’s class to its value, which is obviously the same class
  • sore6 = re8 = 1