Swift 中的 Protocol — 什么是,语法和功能

作者: IT Sectr 发布日期: 2026-06-17 阅读时间: 6 分钟

Protocol 在 Swift 中 — 是一个契约,定义了一组任何采用它的类型必须满足的要求。协议是面向协议编程(POP)的基础 — 这是 Apple 为 Swift 推荐的与经典 OOP 并行的范式。根据 Apple Documentation, 2026,结构体、类和枚举可以采纳协议,这使得架构灵活且可测试。

要点

  • Protocol — 为结构体、类和枚举提供要求的契约
  • Requirements 包括方法、属性、初始化器和下标
  • Protocol Composition 允许组合多个协议
  • POP — 面向协议编程,继承的替代方案
  • Protocol Extensions 为方法添加默认实现

Swift 中的 Protocol 是什么?

Protocol — 是一个抽象接口,定义了一个类型应该能做什么,但不是如何做。在 Swift 中,协议类似于 Java 或 Go 中的接口,但具有额外功能。

协议可以要求:

  • 方法 实例和类型(静态)
  • 属性 带有 { get }{ get set } 指定符
  • 初始化器
  • 下标
  • Associated types(协议级别的泛型)

根据 WWDC 2015,Apple 将面向协议编程作为 Swift 应用程序架构的基本方法引入。与 OOP 不同,类的继承创建了僵化的层次结构,而 POP 提出了协议的组合。这提供了灵活性:一个类型可以符合多个协议,通过 extensions 接收它们的要求和实现。

声明协议的语法

Protocol 使用关键字 protocol 声明,后跟名称和主体。

swift
protocol Drawable {
    func draw(context: CGContext)
    var boundingBox: CGRect { get }
}

类型通过在名称后加冒号来采纳协议:

swift
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 } 指定。

swift
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 可以继承另一个协议,添加新的要求。这创建了契约的层次结构,而不与类僵化绑定。

swift
protocol Vehicle {
    var speed: Double { get set }
    func move()
}

protocol Flyable: Vehicle {
    var altitude: Double { get set }
    func takeOff()
}

采纳 Flyable 的类型必须满足两个协议的要求 — 同时满足 VehicleFlyableSwift 支持协议的多重继承:protocol A: B, C

Protocol Composition

Protocol Composition — 一种机制,允许指定一个类型必须同时符合多个协议,而无需创建新的组合协议。

swift
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 作为类型

Protocol 可以用作变量类型、函数参数或集合元素。这称为 existential type。

swift
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 时,开发者经常会犯一些重复的错误。

  • 忘记 mutating — 协议中的方法被标记为 mutating,但结构体在实现时没有使用该关键字
  • 用 Protocol as type 代替 generic — 在需要具体类型的地方使用 Drawable 而不是 <T: Drawable>
  • 循环协议引用 — 协议通过 associated type 引用自身,但没有正确解决
  • Class-only protocol — 不必要地使用 AnyObject,排除了 struct 和 enum

常见问题

protocol 和 abstract class 有什么区别?

Protocol 只定义要求而不实现(直到 protocol extensions)。Abstract class 可以包含实现和状态。Swift 中没有抽象类 — 它们的作用由带有 extensions 的协议承担。

struct 可以采纳 protocol 吗?

可以,结构体、类和枚举 — 都可以采纳协议。这是 POP 的基础:你不必使用类来组织架构。带有协议的结构体提供值语义和不可变性。

协议中的 associated type 是什么?

Associated type (associatedtype) — 是一个占位符,实现类型自行确定的类型。示例:Collectionassociatedtype Element。这是协议级别的泛型。

可以将协议限制为仅限类吗?

可以,添加从 AnyObject 的继承:protocol MyProtocol: AnyObject。这样只有类可以采纳此协议。这对于弱引用和委托很有用。

如何在运行时检查协议一致性?

使用 is 进行检查,使用 as? 进行转换:if let drawable = item as? Drawable。这只适用于没有 associated types 的协议。

总结

  • Protocol — 方法、属性、初始化器和下标的契约
  • Class, struct, enum — 所有类型都可以采纳协议
  • 继承 协议创建了无僵化耦合的契约层次结构
  • Protocol Composition (&) 无需继承即可组合协议
  • Existential types (any) 和 opaque types (some) — 使用协议的两种方式
  • POP 被 Apple 推荐作为经典类继承的替代方案
  • Protocol Extensions 允许添加默认实现

我们将开发一款交钥匙移动应用程序

IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。

讨论项目

另请阅读