每个Objective-C对象都有一个隐藏的数据结构,这个数据结构是Objective-C对象的第一个成员变量,它就是isa指针。这个指针
指向哪呢?它指向一个类对象(class object
记住它是个对象,是占用内存空间的一个变量,这个对象在编译的时候编译器就生成了,专门来描述某个类的定义),这个类对象包含了Objective-C
对象的一些信息(为了区分两个对象,我把前面提到的对象叫Objective-C对象),包括Objective-C对象的方法调度表,实现了什么协议等
等。这个包含信息就是Objective-C动态能力的根源了。
首先,NSObject的定义是这样的:
@interface NSObject {
Class isa;
}
//把上面的代码简单的转换成C语言就是
struct NSObject{
Class isa;
}
//那个这个Class又是什么呢?在objc.h中我们发现其仅仅是一个结构(struct)指针的typedef定义:
typedefstruct objc_class *Class;
//so,NSObject的定义就可以这样写了:
struct NSObject{
objc_class *isa
}
@interfaceNSObject{
Classisa;
}
//把上面的代码简单的转换成C语言就是
structNSObject{
Classisa;
}
//那个这个Class又是什么呢?在objc.h中我们发现其仅仅是一个结构(struct)指针的typedef定义:
typedefstructobjc_class*Class;
//so,NSObject的定义就可以这样写了:
structNSObject{
objc_class*isa
}
接着往下,我们来看objc_class是个什么东西
struct objc_class {
Class isa;
Class super_class;
const char *name;
long version;
long info;
long instance_size;
struct objc_ivar_list *ivars;
struct objc_method_list **methodLists;
struct objc_cache *cache;
struct objc_protocol_list *protocols;
}
structobjc_class{
Classisa;
Classsuper_class;
constchar*name;
longversion;
longinfo;
longinstance_size;
structobjc_ivar_list*ivars;
structobjc_method_list**methodLists;
structobjc_cache*cache;
structobjc_protocol_list*protocols;
}
在Objective-C中任何的类定义都是对象。即在程序启动的时候任何类定义都对应于一块内存。在编译的时候,编译器会给每一个类生成一个且只
生成一个”描述其定义的对象”,也就是苹果公司说的类对象(class object),他是一个单例(singleton),
而我们在C++等语言中所谓的对象,叫做实例对象(instance object)。对于实例对象我们不难理解,但类对象(class
object)是干什么吃的呢?我们知道Objective-C是门很动态的语言,因此程序里的所有实例对象(instace
objec)都是在运行时由Objective-C的运行时库生成的,而这个类对象(class
object)就是运行时库用来创建实例对象(instance object)的依据。
结论:任何直接或间接继承了NSObject的类,它的实例对象(instacne
objec)中都有一个isa指针,指向它的类对象(class object)。这个类对象(class
object)中存储了关于这个实例对象(instace object)所属的类的定义的一切:包括变量,方法,遵守的协议等等。
但是很奇怪,我们发现在这个objc_class中又看到了isa指针,怎么一层套一层。
这里的isa指向的还是一个objc_class对象,不过这里的对象叫做元类对象(metaclass object).它和类对象(class object)的关系是这样的: 类对象(class object)中包含了类的实例变量,实例方法的定义,而元类对象(metaclass object)中包括了类的类方法(也就是C++中的静态方法)的定义。类对象和元类对象中水果公司当然还会包含一些其它的东西,以后也可能添加其它的内容,但对于我们了解其内存布局来说,只需要记住:类对象存的是关于实例对象的信息(变量,实例方法等),而元类对象(metaclass object)中存储的是关于类的信息(类的版本,名字,类方法等)。要注意的是,类对象(class object)和元类对象(metaclass object)的定义都是objc_class结构,其不同仅仅是在用途上,比如其中的方法列表在类对象(instance object)中保存的是实例方法(instance method),而在元类对象(metaclass object)中则保存的是类方法(class method)。
所有的元类对象(metaclass object)都指向 NSObject的元类对象,到头还是NSObject。一共三次:类对象->元类对象->NSObject元类对象。
下面我以一个有4层继承关系的类的实例变量的内存布局为例.
通过打印D3类的一个实例变量并将那些isa,super_class的地地址记录下来整理得到的关系如下图:
在这里对上图进行一下解释:
矩形表示对象(object),即一块内存;箭头表示指针,isa即isa指针,super表示super_class指针,这些指针是箭头尾部对象
(object)的成员变量,除了“D3实例对象”(最左边的对象),其它对象都是在程序一启动就创建在在内存中的了而且都是单例
(singleton),类对象(class object)和元类对象(metaclass
object)只是用途不一样,其定义都为objc_class结构。
D3对象的内存布局为:从前往后为isa,D1的实例变量,D2的实例变量,D3的实例变量。而isa指针指向的内容就是上图中的“D3类对象”。对于上图,任何类C如果直接或间接继承NSObject 或者其就是NSObject,则有如下结论:
1. 类C的类对象(class object)的super_class都指向了类C父类的类对象(class object), NSObject的类对像的super_class指向0x0
2. 类C的类对象(class object)的isa指针都指向他的元类对象(metaclass object)
3. 类C的元类对象(metaclass
object)的super_class指针指向父类的元类对象(metaclass object),
例外:NSObject的元类对象(metaclass object)的super_class指向NSObject的类对象(class
object).
4. 类C的元类对象(metaclass object)的isa指针指都指向NSObject的元类对象(metaclass object)
NSObject的实例对象(虽然它没有实例变量和实例方法但这个对象仍然存在)其super_class指向地址0x0,因为NSObject没有父类, 这满足上面的结论1。
NSObject的实例对象的isa指向了NSObject的元类对象(metaclass object),这满足上面结论2。
NSObject的元类对象(metaclass object)指向了自己,这也满足上面结论4。