類底層原理面試題

題一

@interface LGPerson : NSObject
- (void)sayHello;
+ (void)sayHappy;
@end

void lgInstanceMethod_classToMetaclass(Class pClass){
    const char *className = class_getName(pClass);
    Class metaClass = objc_getMetaClass(className);
    
    Method method1 = class_getInstanceMethod(pClass, @selector(sayHello));
    Method method2 = class_getInstanceMethod(metaClass, @selector(sayHello));
    Method method3 = class_getInstanceMethod(pClass, @selector(sayHappy));
    Method method4 = class_getInstanceMethod(metaClass, @selector(sayHappy));
    LGLog(@"%s - %p-%p-%p-%p",__func__,method1,method2,method3,method4);
}

void lgClassMethod_classToMetaclass(Class pClass){
    const char *className = class_getName(pClass);
    Class metaClass = objc_getMetaClass(className);
    
    Method method1 = class_getClassMethod(pClass, @selector(sayHello));
    Method method2 = class_getClassMethod(metaClass, @selector(sayHello));
    Method method3 = class_getClassMethod(pClass, @selector(sayHappy));
    Method method4 = class_getClassMethod(metaClass, @selector(sayHappy));
    LGLog(@"%s-%p-%p-%p-%p",__func__,method1,method2,method3,method4);
}

LGPerson *person = [LGPerson alloc];
Class pClass     = object_getClass(person);

lgInstanceMethod_classToMetaclass(pClass);
lgClassMethod_classToMetaclass(pClass);

打印結(jié)果:

lgInstanceMethod_classToMetaclass - 0x1000031a8-0x0-0x0-0x100003140
lgClassMethod_classToMetaclass-0x0-0x0-0x100003140-0x100003140

首先傳入?yún)?shù)pClass,是LGPerson類。
lgInstanceMethod_classToMetaclass方法中,pClass為LGPerson類,metaClass為LGPerson元類。
class_getInstanceMethod從傳入的類或者類的父類中查找指定的實(shí)例方法。

  • class_getInstanceMethod(pClass, @selector(sayHello))中,pClass為LGPerson類,查找sayHello實(shí)例方法,在LGPerson類找到了sayHello方法。
  • class_getInstanceMethod(metaClass, @selector(sayHello))中,metaClass為LGPerson元類,根據(jù)sayHello查找實(shí)例方法,查找鏈路LGPerson元類->NSobject根元類->NSobject類->nil,sayHello在LGPerson類中,所以不能找到。
  • class_getInstanceMethod(pClass, @selector(sayHappy))中,pClass為LGPerson類,根據(jù)sayHello查找實(shí)例方法,查找鏈路LGPerson類->NSobject類->nil,sayHappy在LGPerson元類中,所以不能找到。
  • class_getInstanceMethod(metaClass, @selector(sayHappy))中,metaClass為LGPerson元類,根菌sayHappy查找實(shí)例方法,從LGPerson元類開始根據(jù)sayHappy查找實(shí)例方法,sayHappy在LGPerson元類中,所以找到了。

lgClassMethod_classToMetaclass方法中,pClass為LGPerson類,metaClass為LGPerson元類。
class_getClassMethod方法會先查找到對應(yīng)的元類,再查找方法。

  • class_getClassMethod(pClass, @selector(sayHello))中,pClass為LGPerson類,找到LGPerson元類,無法查找到sayHello方法。
  • class_getClassMethod(metaClass, @selector(sayHello))中,metaClass本身為LGPerson元類
    ,無法查找到sayHello方法。
  • class_getClassMethod(pClass, @selector(sayHappy)),pClass為LGPerson類,找到LGPerson元類,查找到sayHappy方法。
  • class_getClassMethod(metaClass, @selector(sayHappy)),metaClass為LGPerson元類
    查找到sayHappy方法。

題二

       LGPerson繼承自NSObject
        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);

估計很多人都能答,但今天我們研究的是解答這道題的過程中所涉及的一些知識。

class、isKindOfClass、isMemberOfClass

首先我們來看class類方法,經(jīng)過斷點(diǎn)調(diào)試發(fā)現(xiàn)其會進(jìn)入:

Class
objc_opt_class(id obj)
{
#if __OBJC2__
    if (slowpath(!obj)) return nil;
    Class cls = obj->getIsa();
    if (fastpath(!cls->hasCustomCore())) {
        return cls->isMetaClass() ? obj : cls;
    }
#endif
    return ((Class(*)(id, SEL))objc_msgSend)(obj, @selector(class));
}

我們知道實(shí)例的isa是指向類的,類的isa指向元類。根據(jù)源碼理解,如果obj是類,那么就返回自己,如果是實(shí)例就返回其對應(yīng)的類。

isKindOfClass方法,我們?nèi)タ雌湓创a實(shí)現(xiàn):

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

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

isKindOfClass類方法房和實(shí)例方法,區(qū)別在于類方法是調(diào)用ISA而實(shí)例方法是調(diào)用class方法,otherClass是做比較的Class。tcls從cls開始,順著其類的繼承鏈查找,如果找到和otherClass相同則返回YES,最終找不到則返回NO.
isMemberOfClass方法,其源碼實(shí)現(xiàn)為:

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

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

類方法調(diào)用class方法后返回值判斷是否和cls相同,實(shí)例方法調(diào)用ISA方法后返回值判斷是否和cls相同。

題目分析

相關(guān)概念有了了解后我們開始來對題目來一一進(jìn)行分析:

 BOOL re1 = [(id)[NSObject class] isKindOfClass:[NSObject class]]; 

[NSObject class]對應(yīng)的就是NSObject類。
調(diào)用isKindOfClass后,前面的的NSObject類調(diào)用getIsa()后就是NSObject根元類,otherClass即是NSObject類。
進(jìn)入for循環(huán)判斷
第一步:NSObject根元類和NSObject類不相等,NSObject根元類調(diào)用superclass
第二步:NSObject根元類的superclass為NSObject類(這點(diǎn)不明白可以去了解下isa、super走位圖),兩者相等,返回YES.
re1為1.

BOOL re2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]];     

[NSObject class]對應(yīng)的就是NSObject類,調(diào)用isMemberOfClass后,
前面的NSObject類會調(diào)用ISA(),變成了NSObject根元類,和后面的NSObject類比較不相等。re2結(jié)果為0。

BOOL re3 = [(id)[LGPerson class] isKindOfClass:[LGPerson class]];      

[LGPerson class]對應(yīng)的就是LGPerson類,調(diào)用isKindOfClass后,前面的LGPerson類會調(diào)用ISA(),變成了LGPerson元類.
進(jìn)入for循環(huán)判斷
第一步:LGPerson元類和LGPerson類比較不相等,LGPerson元類調(diào)用superclass.
第二步:LGPerson元類的superclass為NSObject根元類,NSObject根元類和LGPerson類比較還是不相等。繼續(xù)superclass。
第三步:NSObject根元類繼續(xù)superclass得到NSObject類,和LGPerson類比較不相等。繼續(xù)superclass
第四步:NSObject類superclass為nil,和LGPerson類比較不相等。并且因?yàn)閚il退出循環(huán),最終返回NO.
re3為0;

BOOL re4 = [(id)[LGPerson class] isMemberOfClass:[LGPerson class]];     

[LGPerson class]對應(yīng)的就是LGPerson類,調(diào)用isMemberOfClass后,前面的LGPerson類會調(diào)用ISA(),變成了LGPerson元類,和后面的NSObject類比較不相等。
re4結(jié)果為0。

BOOL re5 = [(id)[NSObject alloc] isKindOfClass:[NSObject class]];       

[NSObject alloc]得到的是一個NSObject實(shí)例,[NSObject class]得到NSObject類。

調(diào)用isKindOfClass后,前面的的NSObject實(shí)例調(diào)用class方法后就是NSObject類,跟后面的NSObject類比較相等,返回YES.
re5為1.

BOOL re6 = [(id)[NSObject alloc] isMemberOfClass:[NSObject class]];    

[NSObject alloc]得到的是一個NSObject實(shí)例,[NSObject class]得到NSObject類。

調(diào)用isMemberOfClass后,前面的的NSObject實(shí)例調(diào)用class方法后就是NSObject類,跟后面的NSObject類比較相等,返回YES.
re6為1.

BOOL re7 = [(id)[LGPerson alloc] isKindOfClass:[LGPerson class]];       

[LGPerson alloc]得到的是一個LGPerson實(shí)例,[LGPerson class]得到LGPerson類。

調(diào)用isKindOfClass后,前面的的LGPerson實(shí)例調(diào)用class方法后就是LGPerson類,跟后面的LGPerson類比較相等,返回YES.
re7為1.

BOOL re8 = [(id)[LGPerson alloc] isMemberOfClass:[LGPerson class]];

[LGPerson alloc]得到的是一個LGPerson實(shí)例,[LGPerson class]得到LGPerson類。

調(diào)用isMemberOfClass后,前面的的LGPerson實(shí)例調(diào)用class方法后就是LGPerson類,跟后面的LGPerson類比較相等,返回YES.
re8為1.

最終結(jié)果為:

 re1 :1
 re2 :0
 re3 :0
 re4 :0
 re5 :1
 re6 :1
 re7 :1
 re8 :1
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容