面试题答案
一键面试Objective-C运行时机制核心概念
- 类对象(Class Object):
- 每个类在运行时都有一个对应的类对象。类对象存储了该类的相关信息,比如类名、超类(superclass)指针、实例变量的布局信息、方法列表等。例如,对于一个
Person
类,运行时会创建一个代表Person
类的类对象。通过[Person class]
可以获取到这个类对象。 - 类对象是类的实例的模板,实例通过类对象来分配内存、调用方法等。
- 每个类在运行时都有一个对应的类对象。类对象存储了该类的相关信息,比如类名、超类(superclass)指针、实例变量的布局信息、方法列表等。例如,对于一个
- 元类(Meta - Class):
- 元类也是一种类对象,它存储了类方法(以
+
开头的方法)的列表。每个类都有一个与之关联的元类。元类的超类是其类的超类的元类(根元类的超类是NSObject
的元类,NSObject
元类的超类是NSObject
本身)。 - 类方法实际上是存储在元类的方法列表中。当调用一个类方法时,比如
[Person someClassMethod]
,消息是发送给Person
类的元类。
- 元类也是一种类对象,它存储了类方法(以
- 方法列表(Method List):
- 类对象和元类都有方法列表。类对象的方法列表存储实例方法(以
-
开头的方法),元类的方法列表存储类方法。方法列表中的每个方法由一个SEL
(选择器)和一个IMP
(实现)组成。SEL
是方法的唯一标识符,IMP
是方法实际的实现代码的指针。例如,对于Person
类的- (void)sayHello
方法,在类对象的方法列表中,会有一个对应的SEL
为@selector(sayHello)
,以及指向sayHello
方法实现代码的IMP
。
- 类对象和元类都有方法列表。类对象的方法列表存储实例方法(以
runtime在高级特性中的应用原理及实际开发场景
- 消息转发(Message Forwarding):
- 应用原理:当向一个对象发送一条它无法识别的消息时,runtime会启动消息转发机制。首先是动态方法解析,runtime会询问类是否可以动态添加一个处理该消息的方法(
+ (BOOL)resolveInstanceMethod:(SEL)sel
用于实例方法,+ (BOOL)resolveClassMethod:(SEL)sel
用于类方法)。如果动态方法解析没有处理该消息,接着进入备用接收者阶段,runtime会询问对象是否能把消息转发给其他对象处理(- (id)forwardingTargetForSelector:(SEL)aSelector
)。如果备用接收者也没有处理,最后进入完整的消息转发阶段,runtime会创建一个NSInvocation
对象,包含消息的所有信息,开发者可以在- (void)forwardInvocation:(NSInvocation *)anInvocation
方法中手动处理该消息,或者调用父类的forwardInvocation:
方法继续转发。 - 实际开发场景:在开发框架时,可能会遇到一些动态的需求,比如调用一些可能在运行时才会添加的方法。例如,在一些插件化开发中,插件可能会在运行时注册一些方法,主程序在不知道这些方法提前存在的情况下,通过消息转发机制可以动态调用这些方法。
- 应用原理:当向一个对象发送一条它无法识别的消息时,runtime会启动消息转发机制。首先是动态方法解析,runtime会询问类是否可以动态添加一个处理该消息的方法(
- 动态方法解析(Dynamic Method Resolution):
- 应用原理:在消息转发的第一步,runtime会调用类的
+ (BOOL)resolveInstanceMethod:(SEL)sel
(实例方法)或+ (BOOL)resolveClassMethod:(SEL)sel
(类方法)。如果开发者在这些方法中通过class_addMethod
函数动态添加了对应的方法实现,runtime就会重新尝试发送消息,此时新添加的方法就会被调用。 - 实际开发场景:在一些动态功能扩展的场景中很有用。比如,在一个游戏开发中,游戏可能会根据玩家的操作在运行时动态添加一些特殊的技能方法,通过动态方法解析可以在运行时添加这些技能方法的实现并调用。
- 应用原理:在消息转发的第一步,runtime会调用类的
- 关联对象(Associated Objects):
- 应用原理:runtime提供了
objc_setAssociatedObject
、objc_getAssociatedObject
、objc_removeAssociatedObjects
等函数来实现关联对象。通过这些函数,可以在运行时为一个对象动态添加额外的属性,而不需要在类的定义中声明。这些关联对象是基于runtime的散列表实现的,每个对象都有一个关联对象的列表。 - 实际开发场景:在category(类别)中添加属性时非常有用。因为category不能直接添加实例变量,通过关联对象可以实现类似添加属性的效果。例如,在开发一个图片处理的category时,可以通过关联对象为
UIImage
对象添加一些自定义的属性,如图片的来源描述等,而不需要修改UIImage
类的原有代码。
- 应用原理:runtime提供了