Objective-C Runtime:类和对象
Objective-C Runtime:类和对象
镇长Objective-C
Objective-C是一门动态语言。其实Objecitve-C扩展了C语言,加入了面向对象特性和消息传递机制。简单的说,这个扩展的核心是Runtime库,它是Objective-C面向对象的和动态机制的基石。Objective-C是动态的语言,意味着它不仅需要一个编译器,还需要一个运行时系统动态的创建类和对象、进行消息传递和转发。充分理解Runtime机制,可以帮助我们更好的学习Objective-C。下面一起学习Runtime:
类(Class)
在Objective-C中,类和对象都是结构体。从头文件objc/objc.h中,可以查看定义。
1 | typedef struct objc_class *Class; |
查看objc/runtime.h中objc_class结构体的定义
1 | struct objc_class { |
其中
1.isa:指向metaClass(元类)的指针。
2.super_class:执行该类的父类,如果该类是根类(NSObject或NSProxy),则super_class为NULL。
3.version:记录类的版本信息。主要用于对象的序列化,可以通过它识别出不同定义版本中实例变量布局的改变。
4.cache:用于缓存常用的方法。当接收对象收到消息时,根据isa指针去查找相应的对象。实际上,这个对象中有很多方法,只有一少部分经常使用,很多方法不能使用或者根本用不上。这种情况下,如果每次接收到消息都去遍历methodLists,性能较差,所以使用cache保存经常使用的方法,在接收到消息后,首先查找cache,如果没有则查找methodLists,提高查找效率。
对象
在objc/objc.h中,对象的定义
1 | struct objc_object { |
objc_object是一个类的实例的结构体,其中只有一个指向其类的isa指针。当对象发送消息是,运行时库可以根据isa指针找到实例对象所属的类。运行时库会在类的methodLists和父类的methodLists中查找能响应的方法,找到后运行方法。
另外,id是objc_object类型的指针。通过它可以实现类似C++的泛型。
元类(Meta Class)
所有类自身也是一个对象,所以我们可以向类发送消息(调用类方法)。例如,
1 | NSArray *array = [NSArray array]; |
+array消息发送给NSArray类,因为NSArray也是对象,所以它也是objc_object结构体,包含isa指针指向其类。那么,isa指针指向哪里呢?为了调用+array方法,这个类的isa指针必须指向一个包含这些类方法的objc_object结构体。所以就引出了meta-class是一个类对象的类。
当向一个对象发送消息时,会在这个类的方法列表中查找方法;
当向一个类发送消息时,会在这个类的meta-class的方法列表中查找。meta-class 中存放着一个类所有的类方法。
这时可能又发现了一个问题,既然一切皆是类,那么meta-class的isa指针指向哪里呢?在Objective-C设计者为了防止无限循环,所有的meta-class的isa指向基类的meta-class,基类的meta-class指向自身。
上图,虚线是isa的指向,可以看出每个isa都不为空,所以无论什么类型的对象,我们都可以通过isa获取对象信息。实线是superclass指向,通过该它可以方便查找父类,如果是根类在superclass为空。
常用操作
1 | //类名 |
** 成员变量(ivars)及属性 **
在objc_class中,所有的成员变量、属性的信息是放在链表ivars中。ivars是数组,存放着指向每个元素的Ivar指针。以下方法是操作这个字段的。
成员变量操作方法
1 | // 获取类中指定名称实例成员变量的信息 |
注意:class_copyIvarList需要手动释放free();
属性操作方法
1 | // 获取指定的属性 |
方法(methodLists)
1 | // 添加方法 |
class_addMethod方法可以覆盖父类方法的实现,但是不会取代本类已存在的实现,如果存在同名的方法,则会返回NO。如果要修改本类中方法的实现,可以使用method_setImplementation。
class_getInstanceMethod,class_getClassMethod方法和class_copyMethodList不同,前者会搜索父类。
class_replaceMethod如果类中存在同名的,则会替换;如果不存在,会添加。
class_getMethodImplementation方法,该函数再向类实例发送消息是会调用,并返回一个指向方法实现的函数指针。这个函数会比method_getImplementation(class_getInstanceMethod(cls, name))更快。返回的函数指针是一个指向runtime内部的函数,而不一定是方法的实际实现。
class_respondsToSelector函数,通常使用NSObject类的respondsToSelector:或instancesRespondToSelector:方法来实现相同目的。
如果想看具体内容点这里
小结
本文介绍了Runtime运行时中类和对象相关的数据结构,通过数据结构可以更好的理解底层面向对象的实现。另外,列举了一些常用的操作方法。
参考资料:
1.Objective-C 中的类和对象 - Garan no Dou