Protocol 在 Swift 中 — 是一个契约,定义了一组任何采用它的类型必须满足的要求。协议是面向协议编程(POP)的基础 — 这是 Apple 为 Swift 推荐的与经典 OOP 并行的范式。根据 Apple Documentation, 2026,结构体、类和枚举可以采纳协议,这使得架构灵活且可测试。
要点
Protocol — 是一个抽象接口,定义了一个类型应该能做什么,但不是如何做。在 Swift 中,协议类似于 Java 或 Go 中的接口,但具有额外功能。
协议可以要求:
{ get } 或 { get set } 指定符根据 WWDC 2015,Apple 将面向协议编程作为 Swift 应用程序架构的基本方法引入。与 OOP 不同,类的继承创建了僵化的层次结构,而 POP 提出了协议的组合。这提供了灵活性:一个类型可以符合多个协议,通过 extensions 接收它们的要求和实现。
Protocol 使用关键字 protocol 声明,后跟名称和主体。
protocol Drawable {
func draw(context: CGContext)
var boundingBox: CGRect { get }
}
类型通过在名称后加冒号来采纳协议:
struct Circle: Drawable {
let center: CGPoint
let radius: CGFloat
func draw(context: CGContext) {
context.addArc(center: center, radius: radius, ...)
}
var boundingBox: CGRect {
CGRect(x: center.x - radius, y: center.y - radius,
width: radius * 2, height: radius * 2)
}
}
一个类型可以采纳多个协议,用逗号分隔:struct MyType: ProtocolA, ProtocolB。编译器检查每个协议的所有要求是否都得到满足。
Property requirements 使用关键字 var 和访问指定符 { get } 或 { get set } 指定。
protocol UserProtocol {
var name: String { get }
var age: Int { get set }
static var maxAge: Int { get }
mutating func updateName(_ newName: String)
}
协议中的关键字 mutating 表示该方法可以修改 self。结构体必须将此类方法实现为 mutating,类可以省略。Method requirements 使用完整签名指定,包括参数标签。
Protocol 可以继承另一个协议,添加新的要求。这创建了契约的层次结构,而不与类僵化绑定。
protocol Vehicle {
var speed: Double { get set }
func move()
}
protocol Flyable: Vehicle {
var altitude: Double { get set }
func takeOff()
}
采纳 Flyable 的类型必须满足两个协议的要求 — 同时满足 Vehicle 和 Flyable。Swift 支持协议的多重继承:protocol A: B, C。
Protocol Composition — 一种机制,允许指定一个类型必须同时符合多个协议,而无需创建新的组合协议。
func render(_ item: Drawable & Animatable) {
item.draw(context: ...)
item.animate(duration: 0.3)
}
Composition (&) 在函数参数、变量和泛型约束中工作。编译器检查传递的类型是否同时满足所有协议。Composition 在 SwiftUI 中经常使用:some View — 这是带有 composition 的泛型。
Protocol Composition 比创建继承层次结构更受青睐:不需要 protocol A: B, C,可以直接采纳 B & C。这提供了灵活性并减少了耦合。Composition 在函数参数和泛型约束中特别方便,在这些场景中需要临时组合要求而无需创建中间协议。这减少了代码中辅助类型的数量。
Protocol 可以用作变量类型、函数参数或集合元素。这称为 existential type。
var drawableItem: Drawable
let items: [Drawable] = [Circle(...), Rectangle(...)]
func process(drawables: [any Drawable]) {
for item in drawables {
item.draw(context: ...)
}
}
关键字 any(Swift 5.6+)明确指示 existential。没有 any 编译器会发出警告。Swift 还支持 some(不透明类型)来隐藏协议背后的具体类型 — 这是 SwiftUI 中的标准技术。
在使用 protocol 时,开发者经常会犯一些重复的错误。
Drawable 而不是 <T: Drawable>AnyObject,排除了 struct 和 enum常见问题
Protocol 只定义要求而不实现(直到 protocol extensions)。Abstract class 可以包含实现和状态。Swift 中没有抽象类 — 它们的作用由带有 extensions 的协议承担。
可以,结构体、类和枚举 — 都可以采纳协议。这是 POP 的基础:你不必使用类来组织架构。带有协议的结构体提供值语义和不可变性。
Associated type (associatedtype) — 是一个占位符,实现类型自行确定的类型。示例:Collection 有 associatedtype Element。这是协议级别的泛型。
可以,添加从 AnyObject 的继承:protocol MyProtocol: AnyObject。这样只有类可以采纳此协议。这对于弱引用和委托很有用。
使用 is 进行检查,使用 as? 进行转换:if let drawable = item as? Drawable。这只适用于没有 associated types 的协议。
总结
&) 无需继承即可组合协议any) 和 opaque types (some) — 使用协议的两种方式我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。