11-1.【OC】【protocol】Objective-C protocol 的 optional / required 区别是什么?

5 阅读2分钟

在 Objective-C 中,Protocol(协议)定义了一组方法规范。@required@optional 关键字决定了遵循该协议的类**“必须实现”还是“可以选择实现”**这些方法。

两者的核心区别在于 编译器的检查强度运行时的安全处理


1. @required (默认)

如果你不显式指定,协议中的所有方法默认都是 @required

  • 编译期约束:如果一个类声明遵循了协议,但没有实现其中的 @required 方法,编译器会抛出 Warning(警告)。虽然不会导致编译失败,但这是强烈的风险提示。
  • 用途:用于定义协议的核心逻辑。没有这些方法,协议的功能就无法闭环。例如 UITableViewDataSource 中的 tableView:cellForRowAtIndexPath:

2. @optional

使用 @optional 关键字后,其下方定义的方法直到遇到下一个关键字前都是可选的。

  • 编译期约束:类可以选择不实现这些方法,编译器不会报任何警告。
  • 用途:用于定义扩展功能钩子(Hooks) 。例如 UITableViewDelegate 中的各种点击回调,如果你不关心点击事件,就不必实现。

3. 运行时的“安全陷阱”

这是两者在开发中最本质的区别:调用方式不同。

调用 @required 方法

由于编译器保证了实现(理论上),你可以直接调用:

Objective-C

[self.delegate mustDoSomething]; 

调用 @optional 方法(必须检查!)

你绝对不能直接调用 @optional 方法。如果委托方(Delegate)没有实现该方法,直接调用会导致 unrecognized selector sent to instance 崩溃。

标准做法: 在调用前使用 respondsToSelector: 进行检查。

Objective-C

if ([self.delegate respondsToSelector:@selector(optionalMethod)]) {
    [self.delegate optionalMethod];
}

4. 底层实现差异

在 Runtime 层面,协议被存储为 protocol_t 结构体,它内部维护了四个不同的方法列表:

  1. Instance Methods (Required)
  2. Instance Methods (Optional)
  3. Class Methods (Required)
  4. Class Methods (Optional)

当你为一个类动态添加协议或者在运行时查询协议时,Runtime 会根据这些分类来区分哪些方法是必须校验的。


5. 总结对比

特性@required@optional
默认状态
编译器警告未实现时报 Warning不报警告
调用安全性相对安全(依赖警告修复)危险,必须手动检查
主要场景数据源(DataSource)、核心回调配置项、UI 样式定制、非必须回调

💡 深度启发:性能优化

在一些高性能场景下(如 UITableView 频繁滑动),如果每次都调 respondsToSelector: 会有微小的性能损耗。资深的开发者通常会在 setDelegate: 时,通过**位运算(Bitfield)**预先缓存该 Delegate 实现了哪些可选方法。