1. Sample code for interview questions

About isKindOfClass: and isMemberOfClass: there isa very classic interview question, mainly test the understanding of isa bitchain and superclass bitchain as well as assembly debugging, source debugging hands-on ability, next I will have a good analysis of this interview question, be sure to see the end, IsKindOfClass: in conventional analysis is wrong.

Code examples:

// XJPerson inherits from NSObject

void xjKindofDemo(void) {BOOL re1 = [(id) [NSObject class] isKindOfClass:[NSObject class]].BOOL re2 = [(id) [NSObject class] isMemberOfClass:[NSObject class]].BOOL re3 = [(id)[XJPerson class] isKindOfClass:[XJPerson class]].BOOL re4 = [(id)[XJPerson class] isMemberOfClass:[XJPerson class]].NSLog(@" \n 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)[XJPerson alloc] isKindOfClass:[XJPerson class]].BOOL re8 = [(id)[XJPerson alloc] isMemberOfClass:[XJPerson class]].NSLog(@" \n re5 :%hhd\n re6 :%hhd\n re7 :%hhd\n re8 :%hhd\n",re5,re6,re7,re8); * * * * * * * * * * * * * * * * * * * * * * * * * * * * * operation result * * * * * * * * * * * * * * * * * * * * * * * * * * * * *2021- 06- 24 14:16:22.361564+0800 
 re1 :1
 re2 :0
 re3 :0
 re4 :0
2021- 06- 24 14:16:22.361631+0800 
 re5 :1
 re6 :1
 re7 :1
 re8 :1

}
Copy the code

2. General analysis (error)

Objc4-818.2 defines the four related methods as follows:

+ (BOOL)isMemberOfClass:(Class)cls {
    return self->ISA() == cls;
}

- (BOOL)isMemberOfClass:(Class)cls {
    return [self class] == cls;
}

+ (BOOL)isKindOfClass:(Class)cls {
    for (Class tcls = self->ISA(); tcls; tcls = tcls->getSuperclass()) {
        if (tcls == cls) return YES;
    }
    return NO;
}

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

Analysis:

  1. [(id)[NSObject Class] isKindOfClass:[NSObject Class]] + (BOOL)isKindOfClass:(class) CLS, The first time you compare isa of Class NSObject which is the Root metaclass NSObject to Class NSObject, it’s not equal; The second time the parent of the Root metaclass NSObject(Root Meta Class) is compared with Class NSObject(Class), equal, returns YES.

  2. [(id)[NSObject Class] isMemberOfClass:[NSObject Class]] + (BOOL)isMemberOfClass:(class) CLS method, Compare isa of Class NSObject which is the Root metaclass NSObject which is not equal to Class NSObject, return NO.

  3. [(id)[XJPerson Class] isKindOfClass:[XJPerson Class]] + (BOOL)isKindOfClass:(class) CLS, The first time you compare the isa of Class XJPerson(Meta Class) with the ISA of Class XJPerson(Meta Class), it is not equal; NSObject(Root Meta Class) and XJPerson(Class) are not equal. The third time, the parent of the Root metaclass NSObject(Root Meta Class) is compared with the Class XJPerson(Class). The fourth time we get the parent of the root Class NSObject(Class) as nil, we exit the for loop and return NO.

  4. [(id)[XJPerson Class] isMemberOfClass:[XJPerson Class]] + (BOOL)isMemberOfClass:(class) CLS Isa of Class XJPerson(Meta Class) is not equal to Class XJPerson(Class), return NO.

  5. [(id)[NSObject alloc] isKindOfClass:[NSObject class]] call – (BOOL)isKindOfClass:(class) CLS, The first time you compare the ISA of the object [NSObject alloc] that is Class NSObject(Class) to Class NSObject(Class), equal, return YES.

  6. [(id)[NSObject alloc] isMemberOfClass:[NSObject Class]] – (BOOL)isMemberOfClass:(class) CLS method, The Class NSObject(Class) of the comparison object [NSObject alloc] is equal to the Class NSObject(Class). Returns YES.

  7. [(id)[XJPerson Alloc] isKindOfClass:[XJPerson Class]] – (BOOL)isKindOfClass:(class) CLS method, The first time the isa of the object [XJPerson alloc] is compared with the Class XJPerson(Class), equal, returns YES.

  8. [(id)[XJPerson alloc] isMemberOfClass:[XJPerson class]] call – (BOOL)isMemberOfClass: CLS method, Compare the Class XJPerson(Class) of the object [XJPerson alloc] to the Class XJPerson(Class), return YES.

The analysis results are the same as the code runs, but if you break the four methods in the source code, you will find that the + (BOOL)isKindOfClass:(Class) CLS and the – (BOOL)isKindOfClass:(Class) CLS don’t work at all. No surprise, no surprise.

3. Compilation analysis (Correct)

Add a breakpoint, open assembly debugging, and run the source code. IsKindOfClass: calls the objc_opt_isKindOfClass function.

Search the objc_opt_isKindOfClass function in the source code, find its definition code, turn off assembly debugging, break the breakpoint, run the source code, and find that isKindOfClass: method is indeed redirected to the objc_opt_isKindOfClass function.

From objc_opt_isKindOfClass function source can be seen that objC2.0 will take precedence over the above, below according to this function to analyze the case judgment process (only analysis isKindOfClass:, isMemberOfClass: above analysis is correct).

Analysis:

  1. [(id)[NSObject class] isKindOfClass:[NSObject class]]callBOOL objc_opt_isKindOfClass(id obj, Class otherClass)Function, first time to get a classNSObject(Class)theisaThe root metaclassNSObject(Root Meta Class)With the classNSObject(Class)Compare, unequal; Take the root metaclass the second timeNSObject(Root Meta Class)The parent of the class is the classNSObject(Class)With the classNSObject(Class)Compare, equal, returnYES.
  2. [(id)[XJPerson class] isKindOfClass:[XJPerson class]]callBOOL objc_opt_isKindOfClass(id obj, Class otherClass)Function, first time to get a classXJPerson(Class)theisaMetaclassesXJPerson(Meta Class)With the classXJPerson(Class)Compare, unequal; The second time to takeXJPerson(Meta Class)The parent class is also the root classNSObject(Root Meta Class)With the classXJPerson(Class)Compare, unequal; Take the root metaclass for the third timeNSObject(Root Meta Class)The parent class of is the root classNSObject(Class)With the classXJPerson(Class)Compare, not equal. Get the root class for the fourth timeNSObject(Class)The parent classnilIf the conditions are not met, exitforLoop, returnNO.
  3. [(id)[NSObject alloc] isKindOfClass:[NSObject class]]callBOOL objc_opt_isKindOfClass(id obj, Class otherClass)Function, the first time to get an object[NSObject alloc]theisaIs the classNSObject(Class)With the classNSObject(Class)Compare, equal, returnYES.
  4. [(id)[XJPerson alloc] isKindOfClass:[XJPerson class]]callBOOL objc_opt_isKindOfClass(id obj, Class otherClass)Function, the first time to get an object[XJPerson alloc]theisaIs the classXJPerson(Class)With the classXJPerson(Class)Compare, equal, returnYES.

After the above analysis, the results obtained are consistent with the results of program operation, But notice that both the + (BOOL)isKindOfClass:(Class) CLS method and the – (BOOL)isKindOfClass:(Class) CLS are actually redirected to objc_opt_isKindOfClass.

Practice is the test of all things.