Objective-C 和 Swift 中的 Protocol(协议) 都用于定义一组方法、属性或行为的“契约”,但它们在语法、能力、运行时机制和使用方式上存在显著差异。以下是两者的详细对比:
一、基础概念
| 特性 | Objective-C Protocol | Swift Protocol |
|---|---|---|
| 定义方式 | @protocol ... @end |
protocol ... { } |
| 实现方式 | 类通过 <ProtocolName> 声明遵循 |
类/结构体/枚举通过 : ProtocolName 遵循 |
| 是否支持可选方法 | ✅(需配合 @optional) |
❌(默认必须实现),但可通过 @objc + optional 模拟(仅限类) |
| 是否支持扩展(Extension) | ❌ | ✅(可通过 extension 提供默认实现) |
| 是否支持泛型约束 | ❌ | ✅(如 where T: Equatable) |
| 是否支持关联类型(Associated Types) | ❌ | ✅(associatedtype) |
二、语法对比
1. 定义协议
Objective-C:
@protocol MyProtocol <NSObject> // 可继承其他协议
- (void)requiredMethod;
@optional
- (void)optionalMethod;
@end
Swift:
protocol MyProtocol: AnyObject { // 可限制为类类型
func requiredMethod()
var someProperty: Int { get set }
}
⚠️ Swift 协议不能直接定义可选方法,除非标记为
@objc并继承自NSObjectProtocol。
2. 遵循协议
Objective-C:
@interface MyClass : NSObject <MyProtocol>
@end
@implementation MyClass
- (void)requiredMethod { /* 必须实现 */ }
// optionalMethod 可不实现
@end
Swift:
class MyClass: MyProtocol {
func requiredMethod() { }
var someProperty: Int = 0
}
// 若未实现 requiredMethod → 编译错误
三、关键区别详解
1. 可选方法(Optional Requirements)
-
Objective-C:
- 原生支持
@optional。 - 调用前需用
respondsToSelector:判断。
- 原生支持
-
Swift:
- 默认所有方法必须实现。
- 若需可选方法,必须:
@objc protocol MyProtocol { @objc optional func optionalMethod() } - 限制:
- 协议必须标记
@objc(意味着只能被 类 遵循,不能被 struct/enum 遵循)。 - 方法必须兼容 Objective-C(不能有泛型、元组、Swift 特有类型等)。
- 协议必须标记
2. 默认实现(Default Implementation)
-
Objective-C:❌ 不支持。
- 通常通过 Category 或 基类 提供共用逻辑。
-
Swift:✅ 通过 Protocol Extension 提供默认实现:
extension MyProtocol { func defaultMethod() { print("Default implementation") } }- 遵循者可选择是否重写。
- 这是 面向协议编程(POP) 的核心特性。
3. 类型系统与泛型支持
-
Objective-C:
- 协议是运行时概念,无泛型。
- 无法表达“某个类型必须符合多个协议”的复杂约束。
-
Swift:
- 协议是一等公民,支持:
-
协议组合:
func foo(x: A & B & C) -
泛型约束:
func process<T: MyProtocol & Codable>(item: T) -
关联类型(Associated Types):
protocol Container { associatedtype Item var count: Int { get } mutating func append(_ item: Item) }
-
协议组合:
- 协议是一等公民,支持:
4. 值类型支持
Objective-C:协议只能被 类(Class) 遵循(因为基于 runtime 的消息机制)。
-
Swift:协议可被 类、结构体、枚举 遵循。
struct Point: MyProtocol { ... } enum State: MyProtocol { ... }→ 支持更安全、高效的值语义编程。
5. 协议作为类型(Existential Types)
-
Swift 允许将协议作为类型使用(称为 Existential):
let items: [MyProtocol] = [obj1, obj2] func handle(thing: MyProtocol) { ... }- 但若协议含
Self或associatedtype,则不能直接作为类型(需用泛型或some/any关键字,Swift 5.7+)。
- 但若协议含
Objective-C:协议可作为类型(
id<MyProtocol>),但功能有限。
6. 运行时 vs 编译时
-
Objective-C:
- 协议检查主要在 运行时(通过
conformsToProtocol:)。 - 更灵活,但也更容易出错(如未实现 required 方法导致 crash)。
- 协议检查主要在 运行时(通过
-
Swift:
- 协议一致性在 编译时 强制检查(除非使用
@objc optional)。 - 更安全,性能更好(尤其对值类型)。
- 协议一致性在 编译时 强制检查(除非使用
四、互操作性(Interop)
- Swift 协议若标记
@objc,可被 Objective-C 使用。 - Objective-C 协议在 Swift 中自动桥接为 Swift 协议。
- 但 Swift 特性(如关联类型、泛型约束)在 Objective-C 中不可见。
五、总结对比表
| 特性 | Objective-C Protocol | Swift Protocol |
|---|---|---|
| 可选方法 | ✅ 原生支持 | ⚠️ 仅限 @objc 类型 |
| 默认实现 | ❌ | ✅(通过 extension) |
| 值类型支持 | ❌ | ✅(struct/enum) |
| 泛型 & 关联类型 | ❌ | ✅ |
| 协议组合 | 有限(id<A, B>) |
✅(A & B) |
| 编译时安全 | ❌(运行时检查) | ✅ |
| 面向协议编程(POP) | 弱 | 强(核心范式之一) |
| 性能 | 消息派发(较慢) | 静态/虚表派发(更快) |
六、使用建议
- 纯 Swift 项目:优先使用 Swift 协议,利用 POP、默认实现、值类型等优势。
-
混合项目(ObjC + Swift):
- 若需被 ObjC 调用,协议需加
@objc。 - 避免在跨语言协议中使用 Swift 特有特性。
- 若需被 ObjC 调用,协议需加
- 需要可选方法:考虑是否真的需要;否则用默认实现 + 协议扩展更安全。