顾名思义,Objective-C就是面向对象的C,那么,为了在C的基础上实现面向对象,设计者是怎么搭建起这个框架的呢?
首先,得从Cocoa框架最基本的类NSObject说起.
@interface NSObject <NSObject> {
Class isa OBJC_ISA_AVAILABILITY;
}
可以看到NSObject类有一个叫isa的实例变量,类型是Class,Class的定义:
/// An opaque type that represents an Objective-C class.
typedef struct objc_class *Class;
/// Represents an instance of a class.
struct objc_object {
Class isa OBJC_ISA_AVAILABILITY;
};
在runtime.h文件中,我们能发现:
struct objc_class {
Class isa;
#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
} OBJC2_UNAVAILABLE;
在objc_object注释中,我们可以看出,一个objc_object结构体对象代表了一个类的实例.
那么,假设现在有一个类A的实例--对象a1.
那么代表a1的结构体成员isa指向哪了呢?在这里,objc引入了一个类对象的概念(估计是受smalltalk的影响,我瞎猜的).对于类A,也有一个对象Ac来表示他,这个对象,就被称为类对象.
对于类A的所有对象而言,他们的isa都指向了Ac这个对象类.
通过观察objc_class的定义(虽然objc2.0之后苹果已经将其封装,不可见),我们可以发现,类A的类对象,记录类A的父对象类,类名,实例大小,实例变量列表等等,但是第一个成员变量依然是isa,那么对于类对象的isa,他又指向哪里了呢?
这里又引入了一个元类对象的概念,暂且称之为Am.元类对象最大得作用就是他的methodLists所指向全部是类A的类方法,这样,就将类方法和实例方法完全分离开.
对于[a1 instanceMethod]和[A classMethod]的调用,就是向其isa所指向的对象在methodLists寻找函数指针再进行调用,如果没能找到,就进入super_class继续寻找.
现在的问题就是Am这个元类对象的isa又指向何处?
objc为了将这种面向对象的框架设计完整,所有元类对象的都指向一个根元类对象Rm,Rm的isa也指向自己,这样isa的列表在最后就形成了一个闭环.
在Cocoa框架中,这个根元类对象就是NSObject的元类对象.
我在网上找了这幅图,比较清晰的解释其中的关系: