iOS底层番外01-iOS内省方法
iOS内省方法 作为一门面向对象的语言,OC具有内省(Introspection)这样一个强大的特性。用于揭示对象在运行时的详细信息,包括方法响应链、继承树上的位置、遵循的协议等。 下面是一些常用的内省方法。 + (Class)superclass; // 获取类继承链上的父类 - (Class)superclass; // 获取实例的类继承链上的父类 + (BOOL)isMemberOfClass:(Class)cls; // 判断类的元类是否是给定类 - (BOOL)isMemberOfClass:(Class)cls; // 判断实例的类是否是给定类 + (BOOL)isKindOfClass:(Class)cls; // 判断类的元类是否在给定类继承链上 - (BOOL)isKindOfClass:(Class)cls; // 判断实例的类是否在给定类继承链上 + (BOOL)respondsToSelector:(SEL)sel; // 类的元类中是否能查找到指定类方法 - (BOOL)respondsToSelector:(SEL)sel; // 实例的类中是否能查找到指定实例方法 + (BOOL)instancesRespondToSelector:(SEL)sel; // 类中是否能查找到指定实例方法 + (BOOL)conformsToProtocol:(Protocol *)protocol; // 类是否遵循指定协议并实现协议的@required方法 - (BOOL)conformsToProtocol:(Protocol *)protocol; // 实例的类是否遵循指定协议并实现协议的@required方法 一道内省的面试题 下面两个NSLog会输出什么? BOOL objKind = [(id)[NSObject alloc] isKindOfClass:[NSObject class]]; BOOL objMember = [(id)[NSObject alloc] isMemberOfClass:[NSObject class]]; BOOL customKind = [(id)[TheObjectOne alloc] isKindOfClass:[TheObjectOne class]]; BOOL customMember = [(id)[TheObjectOne alloc] isMemberOfClass:[TheObjectOne class]]; BOOL objClassKind = [(id)[NSObject class] isKindOfClass:[NSObject class]]; BOOL objClassMember = [(id)[NSObject class] isMemberOfClass:[NSObject class]]; BOOL customClassKind = [(id)[TheObjectOne class] isKindOfClass:[TheObjectOne class]]; BOOL customClassMember = [(id)[TheObjectOne class] isMemberOfClass:[TheObjectOne class]]; NSLog(@"objKind:%hhd objMember:%hhd customKind:%hhd customMember:%hhd\n",objKind,objMember,customKind,customMember); NSLog(@"objClassKind:%hhd objClassMember:%hhd customClassKind:%hhd customClassMember:%hhd\n",objClassKind,objClassMember,customClassKind,customClassMember); 先想一下再看答案: objClassKind:1 objClassMember:0 customClassKind:0 customClassMember:0 objKind:1 objMember:1 customKind:1 customMember:1 很奇怪,类对象的内省方法差不多全军覆没,我不属于我自己是什么操作?带着问题我们来看一下isMemberOfClass和isKindOfClass源码,而它们又分别有自己的类方法和实例方法。 - (BOOL)isMemberOfClass:(Class)cls { return [self class] == cls; } - (BOOL)isKindOfClass:(Class)cls { for (Class tcls = [self class]; tcls; tcls = tcls->superclass) { if (tcls == cls) return YES; } return NO; } + (BOOL)isMemberOfClass:(Class)cls { return self->ISA() == cls; } + (BOOL)isKindOfClass:(Class)cls { for (Class tcls = self->ISA(); tcls; tcls = tcls->superclass) { if (tcls == cls) return YES; } return NO; } 结合源码和上面类常用的内省方法后面的注释可以看出来实例方法isMemberOfClass和isKindOfClass是找到实例的类的继承链来和指定类作为比较,而类方法是找到自己的元类的继承链和指定类比较。 上面题目中实例调用isMemberOfClass和isKindOfClass方法时使用实例的类和指定类进行比较,而指定类就是实例所属的类,此时实例类毫无疑问在指定类继承链上,所以结果无疑全是真。 再来看类调用isMemberOfClass和isKindOfClass方法。类会在元类的继承链上找是否有自己的位置。理所当然类不会在元类继承链上出现,但是有个意外,NSObject返回为真。这个就不得不又掏出官方的isa走位图了。 可以看到图中根类NSObject的元类为根元类,而根元类的父类是谁?还是NSObject。没办法,谁让所有类都是NSObject的子类。NSObject绕了一圈处在了根元类的继承链上。所以[(id)[NSObject alloc] isKindOfClass:[NSObject class]]结果为真。