面试题答案
一键面试1. @optional方法与@required方法的定义
在Objective-C中,协议(protocol)可以定义方法,其中@required
(默认,可不写)修饰的方法是必须实现的,而@optional
修饰的方法是可选实现的。
2. 消息发送过程
- 消息结构:在Objective-C中,消息发送是通过
objc_msgSend
函数实现的。当一个对象接收到一个消息时,运行时会在对象的类的方法列表中查找对应的方法。消息结构主要涉及SEL
(方法选择器)和IMP
(方法实现指针)。 - @required方法查找:对于
@required
方法,在消息发送时,如果对象的类及其父类的方法列表中都没有找到对应的IMP
,就会进入动态方法解析阶段。例如,在objc-runtime-new.mm
中lookUpImpOrForward
函数,会先尝试在缓存中查找方法,若未找到则在类的方法列表以及父类方法列表中查找。如果最终还是找不到,就会进入动态方法解析等后续流程。 - @optional方法查找:
@optional
方法在消息发送时查找流程基本一致,但区别在于即使最终没有找到实现,也不会像@required
方法那样导致程序崩溃(在没有进行动态方法解析等补救措施的情况下)。因为@optional
方法本身就是可选实现的,所以在运行时找不到实现,程序会继续执行,而不会抛出“unrecognized selector sent to instance”这类错误。
3. 动态方法解析过程
- 动态方法解析机制:当运行时在方法列表中找不到对应的方法实现时,会进入动态方法解析阶段。类可以通过重写
+ (BOOL)resolveInstanceMethod:(SEL)sel
(实例方法)或+ (BOOL)resolveClassMethod:(SEL)sel
(类方法)来动态添加方法实现。 - @required方法动态解析:对于
@required
方法,如果在动态方法解析阶段依然没有成功添加方法实现,就会进入备用接收者和完整转发流程,最终如果还是无法处理该消息,就会导致程序崩溃。 - @optional方法动态解析:
@optional
方法同样会进入动态方法解析阶段,但即使动态解析没有成功添加方法实现,程序也不会崩溃,而是继续执行,因为它是可选的。例如,在开发中如果一个类遵循了某个协议,但没有实现其中@optional
方法,在发送该方法消息时,若动态解析失败,程序不会因这个未实现的@optional
方法而崩溃。
通过runtime源码分析可知,@optional
方法与@required
方法在消息发送和动态方法解析过程中,主要区别在于对未找到方法实现时的处理方式,@optional
方法更具灵活性,不会因未实现而导致程序崩溃。