简单更新一道元类面试题
题目就是:下面这个程序的输出的结果是什么?
@interface NSObject(Test)
+ (void) test;
@end
@implementation NSObject(Test)
- (void) test
{
NSLog(@"%@",NSStringFromSelector(_cmd));
return;
}
@end
int main(int argc, char * argv[]) {
@autoreleasepool {
[NSObject test];
[[NSObject new] test];
}
return 0;
}
实际上答案就在下面这张图上:
20180706222710673.png
Class的结构如下所示:
20180706223108421.png
isa: 实例的isa指向Class,Class的isa指向对应的元类
super_class: 指向父类的类指针
name: 类的名字
version: 类的版本
info: 类的一些信息,什么信息不清楚
instance_size: 实例变量的大小
ivars: 类的成员变量
methodLists: 保存类的成员方法
cache: 保存最近调用的一些方法,用于优化方法查找
protocols: 保存类实现的一些协议
类的实例方法是存储在类的methodLists中
而类方法则是存储在元类的methodLists中,
因此根据上图,NSObject的元类的superclass是指向Class,当调用[NSObject test]的时候,因为这是一个类方法调用,所以从元类中查找签名为test的方法,没有发现,然后再沿superclass继续查找,结果在Class中查找到该方法,于是调用该方法输出。但如果将NSObject的分类,换成其他类的分类,如NSString,会发现程序崩溃,这是因为签名为test的函数在NSString中,而当我们进行类方法调用的时候,最后会查找到NSObject的Class中,但该Class中并没有对应的方法签名,于是再沿superclass向上查找,由于NSObject的superclass是nil,于是抛出unrecognized selector。
网友评论