每个Objective-C对象都有一个隐藏的数据结构,这个数据结构是Objective-C对象的第一个成员变量,它就是isa指针。
在NSObject.h里面:
@interface NSObject <NSObject> {
Class isa OBJC_ISA_AVAILABILITY;
}
再点开 Class 的定义:
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class super_class OBJC2_UNAVAILABLE;
const char *name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE;
struct objc_ivar_list *ivars OBJC2_UNAVAILABLE;
struct objc_method_list **methodLists OBJC2_UNAVAILABLE;
struct objc_cache *cache OBJC2_UNAVAILABLE;
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE;
#endif
}
这一些定义对于懂的人自然懂,不会的人根本看不懂。建议看完下面的例子,再点开参考里面的链接仔细看一遍。
现在我们知道的是,对于我们新建的一个类,都会有一个隐藏的属性isa,可以通过它进行一些访问。
我们现在新建一个类Parent,继承于NSObject, 里面有成员方法-(void)selectorP,类方法+(void)ClassSelectorP。
再新建一个类Child,继承于Parent,里面有成员方法-(void)selectorC, 类方法+(void)ClassSelectorC。
现在我们新建一个实例Child* child = [Chlid new];
1,当我们调用[child class] 的时候,child就会通过isa指针去找到Child的class。
2,当我们调用[child superclass]的时候,child 通过isa找到Child的class,再通过super_class,找到Parent的class。
在这里,再普及objc_class 的两种类型:
class 实例对象(child、Child)的isa指向的结构体;
metaclass class的isa指向的一个结构体;
3,接着,调用[child SelectorC],child通过isa找到Child的class,在class(注意看上面 struct objc_class 的定义)的方法列表里面找到SelectorC;
4,再试着调用[child SelectorP],child通过isa找到Child的class,发现class里面并没有这个方法,通过class里面的super_class找到Parent的class,在里面的方法列表找到了SelectorP;
5,再是类方法[Child ClassSelectorC],Child(请注意,大写)通过isa找到Child的class,通过class的isa找到Child的metaclass,在metaclass的方法列表里面找到了ClassSelectorC;
6,再试着调用[Child ClassSelectorP],Child通过isa找到Child的class,通过class的isa找到Child的metaclass,发现metaclass里面并没有这个方法,通过metaclass里面的super_class找到Parent的metaclass,在里面的方法列表找到了ClassSelectorP;
- (void)viewDidLoad {
[super viewDidLoad];
Class clazz = [self class];
Class clarr = [AroundMapController class];
Class metalclazz = objc_getMetaClass("AroundMapController");
if (class_respondsToSelector(metalclazz, @selector(viewWillAppear:))) {
NSLog(@"ok");
}
if (clarr == clazz) {
NSLog(@"2 ok");
}
}
这个是验证runtime的机制,可以把这段代码复制到自己的controller.m里面,运行一下。记得把AroundMapController改成自己的controller的名字,还有引入头文件<objc/runtime.h>
这是几个例子基本上已经涵盖了大多数调用的情况。
细心的朋友可能已经发现,上面的例子中,child通过isa找到的类对象,其实就是Child 通过isa找到的class。(如果能理解这一点,基本上也算对objectC的isa机制也算入门)
最后为了理解class和metaclass的作用,大家可以换位思考一下,如果我们作为runtime的设计者,当开发者新建出来一个实例对象child的时候,我们应该存储child的属性和方法,同时又该如何响应其方法调用,最后还要记录与Parent之间的继承关系。
这时候,再来看看,这种图。可以加深对isa机制的理解:
参考
http://www.cocoachina.com/ios/20141018/9960.html
http://blog.csdn.net/jasonblog/article/details/7246822
http://blog.csdn.net/totogo2010/article/details/8081253
--问答题---
如果给你一个child的实例对象,要如何才能访问到它的父类的静态方法ClassSelectorP?