Objc - 对象之类对象和元类对象

Objc 中的类(Class)

众所周知,在 Objc 中所有的对象都由类实例化而来,殊不知类本身也是一种对象
在 Objc 中几乎所有的类都是 NSObject 的子类,NSObject类定义如下(忽略方法声明):

@interface NSObject <NSObject> {
Class isa OBJC_ISA_AVAILABILITY;
}
@end

这个isa是什么呢?在 objc.h 中我们发现它仅仅是一个 typedef 的结构体(struct)定义,如下:

typedef struct objc_class *Class;

同样的objc_class又是什么呢?在 Objc2.0 中 objc_class定义如下:

struct objc_class {
Class isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class super_class OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;

这里又出现了一个isa指针,这个 isa和上一个有什么区别和联系?

答:其实在 Objc 中任何类的定义都是一个对象。在编译的时候,编译器会给每一个类生成且只生成一个「描述其定义的对象」,也就是苹果公司所说的类对象(class object);因为 Objc 和是一门动态语言,程序中所有的实例对象(instance object)是在运行时库生成的,而这个类对象(class object)就是运行时库用来创建实例对象(instance object)的依据。

再回到之前的问题,为什么实例对象(instance object)的isa指针指向的类对象(class object)里面还有一个isa指针?而这个类对象(class object)的 isa 指向的仍然是一个objc_class,它就是元类对象(metaclass object);那么实例对象(instance object)、类对象(class object)、元类对象(metaclass object)之间的关系是怎样的呢?如下图:

类关系图

类对象(class object)

类对象的实质

类对象是由编译器创建的;即在编译时所谓的类,就是指类对象

官方文档中这样描述:The class object is the compiled version of the class.

任何直接或间接继承了 NSObject 的类,它的实例对象(instance object)中都有一个isa指针,指向它的类对象(class object)。这个类对象(class object)中存储了关于这个实例对象(instance object)所属的类定义的一切:包括变量、方法、遵守的协议等。因此类对象(class object)能访问所有关于这个类的信息,利用这些信息可以产生一个新的实例对象(instance object),但是类对象不能访问任何实力对象的内容。
当调用一个类方法(class method)时,例如:[NSObject alloc],事实上是发送了一个消息给它的类对象。

类对象和实例对象的区别

尽管类对象保留了一个类实例的原型,但它并不是实例本身;它没有自己的实例变量,也不能执行那些类的实例方法

类对象与类名

在代码中,类对象由类名表示。

举个例子:定义类 Person 继承 NSObject

int versionNumber = [Person version];

在上面的例子中,Person 类从 NSObject 继承 version方法来返回类的版本号;只有在消息表达式中作为接受者时,类名才代表类对象。

另外,类对象和其他对象一样也是id类型,例如:

id clazz = [anyObject class];
id pClazz = [Person class];

总之,类对象是一个功能完整的对象,所以也能被动态识别(dynamically typed)接收消息,从其他类继承方法。特殊之处在于它们是由编译器创建的,缺少它们自己的数据结构(实例变量),只是在运行时产生实例的代理。

元类对象(metaclass object)

元类对象的实质

实际上,类对象是元类对象的一个实例,元类对象描述了一个类对象,就像类对象描述了普通的实例对象一样。不同的是元类的方法列表是类方法的集合,由类对象的选择器来响应;当一个类发送消息时候,objc_msgSend会通过类对象的isa指针定位到元类,并检查元类的方法列表(包括父类)来决定调用哪个方法。元类代替了类对象描述了类方法,就像类对象代替实例对象描述了实例化方法。

很显然,元类也是对象,也应该是其他类的实例,实际上元类是根元类(root class’s metaclass)的实例,而根元类是其自身的实例,即根元类的 isa 指针指向自身。

类的super_class指向其父类,而元类的 super_class 则指向父类的元类;元类的 super_class 链与类的super_class链平行,所以类方法的继承与实例方法的继承也是平行的。而根元类(root class’s metaclass)的 super_class指向根类(root class),这样整个指针链就链起来了。

综上所述: 类对象(class object)保存的是关于实例对象的信息(ivar,实例方法等),而元类对象(metaclass object)存储的是关于类的信息(类的版本,名字,类方法等)
要注意的是,类对象和元类对象的定义都是objc_class结构。其不同仅仅是在用途上,比如其中的方法列表在类对象(class object)中保存的是实例方法(instance method),而在元类对象(metaclass object)中保存的则是类方法(class method)

类对象和元类对象的相关方法

object_getClass

object_getClass跟随实例的isa指针,返回此实例所属的类,对于实例对象(instance object)返回的是类(class),而对于类(class)则返回的是元类(metacalss)

class

class方法对于实例对象(instance object)会返回类(class),但对于类(class)则不会返回元类(metaclass),而只会返回类本身,即[@“instance” class]则返回的是__NSCFConstantString;而[NSString class]则返回的是 NSString

class_isMetaClass

class_isMetaClass判断某类是否是元类

objc_allocateClassPair

使用objc_allocateClassPair可在运行时创建新的类对与元类对,使用class_addMethodclass_addIvar可向类中增加方法和实例变量,最后使用objc_registerClassPair注册后,就可以使用此类了。

参考资料

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值