Swift 协议

Swift 协议(Protocol)详解

在 Swift 中,协议(Protocol) 是一种定义行为契约的机制。它不实现功能,只声明方法、属性、下标等要求,任何类型(类、结构体、枚举)只要符合协议,就必须实现这些要求。


1. 基本语法

protocol SomeProtocol {
    // 协议内容
    var property: Int { get set }        // 可读可写属性
    func method(param: String) -> Bool   // 必须实现的方法
    static func staticMethod()           // 静态方法
}

2. 采用协议(Conformance)

struct MyStruct: SomeProtocol {
    var property: Int                    // 必须实现
    func method(param: String) -> Bool { // 必须实现
        return param.count > 5
    }
    static func staticMethod() {         // 必须实现
        print("Static method")
    }
}

3. 协议作为类型使用

协议可以像其他类型一样使用:

func process(item: SomeProtocol) {
    print(item.property)
}

let obj = MyStruct(property: 10)
process(item: obj)  // 多态

4. 属性要求

protocol FullyNamed {
    var fullName: String { get }        // 至少可读
    var nickname: String { get set }    // 可读可写
}

注意:协议只关心 get/set 能力,不关心是 var 还是计算属性。

struct Person: FullyNamed {
    var fullName: String { "John Doe" }     // 计算属性(只读)
    var nickname: String = "JD"             // 存储属性
}

5. 方法要求

protocol Randomizable {
    mutating func randomize()               // 可变方法(用于 struct/enum)
    static func defaultValue() -> Self      // 类型方法
}

类中不需要 mutating,因为类是引用类型。


6. 初始化器要求

protocol Initializable {
    init(value: Int)
}

struct Counter: Initializable {
    var count: Int
    init(value: Int) {
        self.count = value
    }
}

类采用协议时,若协议要求初始化器,需加 required

class MyClass: Initializable {
    required init(value: Int) { ... }
}

7. 协议继承

protocol Named {
    var name: String { get }
}

protocol Aged {
    var age: Int { get }
}

protocol PersonProtocol: Named, Aged {     // 继承多个协议
    func introduce()
}

8. 协议组合(Protocol Composition)

func wishHappyBirthday(to person: Named & Aged) {
    print("Happy birthday \(person.name), you're \(person.age)!")
}

let john = Person(name: "John", age: 30)
wishHappyBirthday(to: john)  // 同时满足 Named 和 Aged

9. 协议扩展(Protocol Extension)

为协议提供默认实现

protocol Greetable {
    var name: String { get }
    func greet()
}

extension Greetable {
    func greet() {
        print("Hello, \(name)!")
    }
}

struct User: Greetable {
    var name: String
}

// User 自动获得 greet() 实现
let user = User(name: "Alice")
user.greet()  // 输出: Hello, Alice!

可通过扩展为协议添加新功能,甚至条件扩展:

extension Greetable where Self: Equatable {
    func isSame(as other: Self) -> Bool {
        return self == other
    }
}

10. 常用系统协议

协议作用
Equatable支持 == 比较
Hashable可作为 Dictionary 键
Comparable支持 < > <= >=
Codable自动编码/解码 JSON
IdentifiableSwiftUI 中标识唯一对象
CaseIterable枚举自动生成 allCases

示例:

struct Point: Equatable, Codable {
    var x: Int
    var y: Int
}

11. 协议与类专属(class-only)

使用 AnyObject 限制仅类可采用:

protocol Delegate: AnyObject {
    func didFinish()
}

class MyViewController {
    weak var delegate: (any Delegate)?   // Swift 5.7+ 写法
}

Swift 5.7+ 推荐使用 any Delegate,旧写法 Delegate?


12. 存在类型(Existential)与 any

let items: [any Greetable] = [User(name: "A"), Person(name: "B")]

any Protocol 表示“某个符合该协议的类型”,用于泛型擦除场景。


小结:协议的核心价值

特性说明
抽象行为定义“做什么”,不关心“怎么做”
多态不同类型统一接口
默认实现通过扩展减少重复代码
组合灵活协议组合、继承、条件扩展
面向协议编程(POP)Swift 推荐的编程范式

推荐实践

// 优先使用协议而非继承
protocol Payable { func pay() }
extension Payable { func pay() { print("Paid") } }

// 多个小协议优于一个大协议
protocol Walkable { func walk() }
protocol Swimmable { func swim() }

需要代码示例项目?还是想看 协议与泛型结合POP 设计模式?欢迎继续提问!

文章已创建 2588

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部