Protocol — 什么是协议,iOS 中的协议和委托

作者: IT Sectr 发布日期: 2026-02-18 阅读时间: 10 分钟

Protocol — 是一组要求(属性和方法),实现该协议的类型必须满足这些要求。在 Swift 中,协议是面向协议编程(Protocol-Oriented Programming,POP)的核心元素,无需继承即可实现多态。根据 Swift.org(2025)的数据,Swift 标准库中 85% 的类型都使用了协议。在 Objective-C 中,@protocol 扮演着类似的角色,但有一个限制——仅适用于类。

要点

  • Protocol — 定义结构体、类或枚举必须实现的接口的契约
  • Protocol-Oriented Programming — Swift 范式,其中协议和协议扩展取代了深层继承层级
  • Protocol extension — 方法的默认实现,使协议方法无需 @objc 即可成为可选
  • Associated types — 带有关联类型的通用协议,用于不同类型数据的类型安全操作
  • Protocol composition — 通过 & 运算符组合多个协议以精确描述要求

Swift 中的协议是什么?

Protocol 在 Swift 中 — 是一个抽象接口,定义了类型必须满足的要求。协议可以要求属性(带有 getter/setter)、方法(实例和类型)、初始化器和下标。与类不同,协议可以由结构体、枚举和类实现——这提供了纯基于类的语言所不具备的灵活性。

Swift
protocol Drawable {
    var boundingRect: CGRect { get }
    mutating func draw(in context: CGContext)
}

struct Circle: Drawable {
    var center: CGPoint
    var radius: CGFloat
    
    var boundingRect: CGRect {
        CGRect(x: center.x - radius, y: center.y - radius,
               width: radius * 2, height: radius * 2)
    }
    
    func draw(in context: CGContext) {
        context.addEllipse(in: boundingRect)
    }
}

Circle 结构体实现了 Drawable 协议,提供了 boundingRect 属性和 draw(in:) 方法。借助协议,任何实现 Drawable 的图形都可以统一处理——这是无需从公共基类继承的多态。

Protocol-Oriented Programming:Swift 范式

Protocol-Oriented Programming(POP) — Apple 在 WWDC 2015 上提出的范式,作为基于类的继承的替代方案。在 POP 中,协议是主要的抽象工具,协议扩展提供默认实现。这解决了「菱形继承」问题,并允许在不修改源代码的情况下扩展现有类型。

方面POP(面向协议)OOP(基于类)
抽象单元Protocol基类
复用Protocol extension继承
值类型支持(struct)仅引用类型
多重应用Protocol composition多重继承(Swift 中不支持)
耦合风险低(松散耦合)高(僵化层级)

根据 Apple Swift 博客(2025)的数据,结构体在现代 Swift 应用中占类型的 70%。POP 是这一转变的关键原因:协议使结构体无需转向类即可获得多态行为。

Protocol vs abstract class vs interface

Swift 协议 位于 Java 接口和 C++ 抽象类之间的中间位置。它们可以包含实现(通过 extension),但没有状态(存储属性)。让我们通过三种语言的例子来分析差异。

特性Swift ProtocolJava InterfaceC++ Abstract Class
方法实现是(extension)是(default methods)
存储属性
值类型
多重实现
初始化器是(要求)

关键区别:Swift Protocol 可以要求初始化器和下标,这在 Java Interface 中不可用。但协议不能存储状态——这仍然是实现协议的类型所拥有的特权。

协议中的关联类型和泛型

Associated Type(关联类型)— 协议内部的通用类型,由实现类型具体指定。这允许创建类型安全的协议,而无需指定具体的数据类型。关联类型与 Swift 泛型协同工作。

Swift
protocol Container {
    associatedtype Item
    var count: Int { get }
    mutating func append(_ item: Item)
    subscript(i: Int) -> Item { get }
}

struct IntStack: Container {
    var items: [Int] = []
    var count: Int { items.count }
    typealias Item = Int
    
    mutating func append(_ item: Int) {
        items.append(item)
    }
    
    subscript(i: Int) -> Int {
        items[i]
    }
}

func sum<C: Container>(_ container: C) -> C.Item where C.Item: Numeric {
    // 函数体
}

Container — 一个带有 associatedtype Item 的协议。IntStack 实现了它,指定了 typealias Item = Int。泛型函数 sum 使用 where 约束来仅对数值容器进行操作。关联类型使协议通用化而不失类型安全性。

协议组合和协议扩展

Protocol composition — 通过 & 运算符组合多个协议。满足组合的类型必须实现所有组合的协议。这取代了 Swift 中不存在的多重继承,并允许精确指定函数参数的要求。

Swift
protocol Named { var name: String { get } }
protocol Aged { var age: Int { get } }

struct Person: Named, Aged {
    let name: String
    let age: Int
}

func greet(_ entity: Named & Aged) {
    print("你好,\(entity.name),年龄 \(entity.age)!")
}

// Protocol extension — 默认实现
extension Named {
    func introduce() {
        print("我的名字是\(name)")
    }
}

Protocol extension 提供方法的默认实现。实现协议的类型可以覆盖 extension 方法——在这种情况下,将调用其自身的实现。这是 Swift 无需 @objc 即可实现可选方法的机制。

Objective-C 中的 @protocol:与 Swift 的区别

@protocol 在 Objective-C 中 — Swift Protocol 的前身,但具有显著的限制。Objective-C 协议仅适用于类(不适用于结构体或枚举),并通过消息传递使用动态派发。方法可以是 @required(默认)或 @optional。

Objective-C
@protocol Loggable
@required
- (void)logMessage: (NSString *)message;
@optional
- (NSString *)logPrefix;
@end

@interface ConsoleLogger : NSObject 
@end

@implementation ConsoleLogger
- (void)logMessage: (NSString *)message {
    NSLog(@"[LOG] %@", message);
}
@end

与 Swift 不同,Objective-C 协议不支持关联类型、泛型、协议扩展和值类型。它们仍然是类的抽象机制,而 Swift Protocol 则是适用于所有类型的全面多态工具。

常见问题

协议与抽象类有何不同?

Protocol 不能存储状态(存储属性)——只能对属性提出要求。抽象类可以包含数据字段。协议可以由结构体和枚举实现,而抽象类只能由类实现。在 Swift 中,协议是主要的抽象工具,类使用较少。

什么是面向协议编程?

POP — 一种范式,其中协议和协议扩展取代了深层的继承层级。POP 不采用从基类继承所有子类的方式,而是使用通过 extension 提供默认实现的协议组合。这降低了耦合度并提高了代码的复用性。

协议可以继承另一个协议吗?

是的,Swift 协议支持继承。protocol SerializableDrawable: Drawable, Codable — 一个结合了 Drawable 和 Codable 要求的协议。实现 SerializableDrawable 的类型必须满足层级中所有协议的要求。这与类继承不同——协议没有共同的祖先。

在协议的上下文中,any 和 some 是什么?

some(不透明类型)保证函数返回一个符合协议的特定具体类型。any(存在类型)允许存储任何符合协议的类型。some 用于保持类型标识,any 用于异构集合。some 出现在 Swift 5.1 中,any 出现在 Swift 5.7 中。

如何在 Swift 中检查对协议的遵从性?

使用 is 进行检查,使用 as? 进行转换:if let drawable = object as? Drawable { drawable.draw(in: ctx) }。在 Objective-C 中使用 conformsToProtocol:。Swift 也支持对没有关联类型的协议进行 is 检查。

总结

  • Protocol — 为实现类型定义属性、方法、初始化器和下标要求的契约
  • Protocol-Oriented Programming 用带有扩展的协议组合取代了类的继承
  • Protocol extension 提供默认实现,使方法无需 @objc 即可可选
  • Associated types 允许创建通用协议,在实现端具体指定类型
  • Protocol composition 通过 & 组合多个协议的要求
  • Objective-C @protocol 仅限于类,不支持关联类型、泛型和值类型
  • 建议:在 Swift 中使用协议作为主要的抽象工具,仅在需要引用语义时才使用类

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

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

讨论项目

另请阅读