底层经典面试题

前言:先来张熟悉又陌生的图:

isa流程图.png

【面试题一】iskindOfClass& isMemberOfClass 的理解
下面代码,怎么打印,并分析原因

int main(int argc, const char * argv[]) {
    @autoreleasepool {
      //-----使用 iskindOfClass & isMemberOfClass 类方法
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);  
//------iskindOfClass & isMemberOfClass 实例方法
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);
    }
    return 0;
}

打印如下:

re1 :1
re2 :0
re3 :0
re4 :0
re5:1
re6:1
re7:1
re8:1

结果已给,你细品,你细细的品;接下来,解释一波,有错,请留言,不要发红包。

源码分析一波

-isKindOfClass 源码解析(实例方法 & 类方法)

//--isKindOfClass---类方法、对象方法
//+ isKindOfClass:第一次比较是 获取类的元类 与 传入类对比,再次之后的对比是获取上次结果的父类 与 传入 类进行对比
+ (BOOL)isKindOfClass:(Class)cls {
   // 获取类的元类 vs 传入类
   // 根元类 vs 传入类
   // 根类 vs 传入类
   // 举例:LGPerson vs 元类 (根元类) (NSObject)
   for (Class tcls = self->ISA(); tcls; tcls = tcls->superclass) {
       if (tcls == cls) return YES;
   }
   return NO;
}

//- `isKindOfClass`:第一次是获取对象类 与 传入类对比,如果不相等,后续对比是继续获取上次 类的父类 与传入类进行对比
- (BOOL)isKindOfClass:(Class)cls {
/*
获取对象的类 vs 传入的类 
父类 vs 传入的类
根类 vs 传入的类
nil vs 传入的类
*/
   for (Class tcls = [self class]; tcls; tcls = tcls->superclass) {
       if (tcls == cls) return YES;
   }
   return NO;
}

  • isMemberOfClass源码解析(实例方法 & 类方法)
//-----类方法
//+ isMemberOfClass : 获取类的元类,与 传入类对比
+ (BOOL)isMemberOfClass:(Class)cls {
    return self->ISA() == cls;
}
//-----实例方法
//- isMemberOfClass : 获取对象的类,与 传入类对比
- (BOOL)isMemberOfClass:(Class)cls {
    return [self class] == cls;
}

"强行解释一波"是有依据的,总结如下:

  • isKindOfClass

    • 类方法:元类 --> 根元类 --> 根类 --> nil传入类的对比
    • 实例方法:对象的类 --> 父类 --> 根类 --> nil传入类的对比
  • isMemberOfClass

    • 类方法: 类的元类传入类 对比
    • 实例方法:对象的父类传入类 对比

案例代码执行结果分析

根据源码的分析,来分析代码执行的结果为什么是0或者1

使用类方法结果解析

  • re1 :1 ,是 NSObjectNSObject 的对比,使用 +isKindOfClass

    • NSObject(传入类,即根类) vs NSObject的元类即根元类-- 不相等
    • NSObject(传入类,即根类) vs 根元类的父类即根类 -- 相等,返回1
  • re2 :0 ,是 NSObjectNSObject 的对比,使用 +isMemberOfClass

    • NSObject根类(传入类) vs NSObject的元类即根元类 -- 不相等
  • re3 :0 ,是 LGPersonLGPerson 的对比,使用 +isisKindOfClass

    • LGPerson(传入) vs LGPerson的元类即元类LGPerson -- 不相等
    • LGPerson(传入) vs 元类LGPerson的父类即根元类 -- 不相等
    • LGPerson(传入) vs 根元类的父类即根类 -- 不相等
    • LGPerson(传入) vs 根类的父类即 nil -- 不相等
  • re4 :0 ,是 LGPersonLGPerson 的对比,使用 +isMemberOfClass

    • LGPerson(传入) vs 元类 -- 不相等

使用实例方法结果解析

  • re5 :1 ,是 NSObject对象NSObject 的对比,使用 -isKindOfClass

    • NSObject(传入类,即根类) vs 对象的类即NSObject根类 -- 相等
  • re6 :1 ,是 NSObject对象NSObject 的对比,使用 -isMemberOfClass

    • NSObject(传入类,即根类) vs 对象的类即NSObject根类 -- 相等
  • re7 :1 ,是 LGPerson对象LGPerson 的对比,使用 -isKindOfClass

    • LGPerson(传入类) vs 对象的类即LGPerson -- 相等
  • re8 :1 ,是 LGPerson对象LGPerson 的对比,使用 -isMemberOfClass

    • NSObject(传入类) vs 对象的类即LGPerson -- 相等

你可能感兴趣的:(底层经典面试题)