文章目录

Swift 协议:protocol 定义与实现

发布于 2026-04-03 14:43:36 · 浏览 6 次 · 评论 0 条

Swift 协议:protocol 定义与实现

在 Swift 中,协议(protocol)是一种定义方法、属性或其他功能要求的蓝图。任何遵循该协议的类型(如结构体、类或枚举)都必须提供这些要求的具体实现。使用协议可以让你编写更灵活、可复用和解耦的代码


定义一个基本协议

  1. 打开 Xcode 或任意文本编辑器,创建一个新的 Swift 文件(例如 MyProtocol.swift)。
  2. 输入以下代码来定义一个名为 Describable 的协议:
protocol Describable {
    var description: String { get }
}

这段代码表示:任何遵循 Describable 协议的类型,都必须提供一个名为 description 的只读字符串属性。

  1. 注意:协议中声明的属性不需要指定存储还是计算,只需要说明它是只读(get)还是可读写(get set)。

让结构体遵循协议

  1. 定义一个结构体并让它遵循 Describable 协议:
struct Person: Describable {
    let name: String
    let age: Int

    var description: String {
        return "姓名:\(name),年龄:\(age)"
    }
}
  1. 验证协议是否被正确实现:

    • 结构体 Person 在类型名后加上冒号和协议名 : Describable,表示它遵循该协议。
    • 它提供了 description 属性的实现,符合协议要求。
  2. 测试功能是否正常:

let p = Person(name: "张三", age: 25)
print(p.description) // 输出:姓名:张三,年龄:25

让类遵循协议

  1. 创建一个类并实现同一协议:
class Car: Describable {
    let brand: String
    let model: String

    init(brand: String, model: String) {
        self.brand = brand
        self.model = model
    }

    var description: String {
        return "\(brand) \(model)"
    }
}
  1. 使用该类:
let myCar = Car(brand: "Tesla", model: "Model 3")
print(myCar.description) // 输出:Tesla Model 3

协议中的方法要求

  1. 扩展协议,加入方法要求:
protocol Resizable {
    func resize(to size: Double) -> Bool
    mutating func resetSize()
}
  • resize(to:) 是一个返回 Bool 的实例方法。
  • resetSize() 前有 mutating 关键字,表示该方法可能修改值类型的自身状态(对类无效,但对结构体和枚举必需)。
  1. 让结构体实现该协议
struct Rectangle: Resizable {
    var width: Double
    var height: Double

    func resize(to size: Double) -> Bool {
        if size > 0 {
            width = size
            height = size
            return true
        }
        return false
    }

    mutating func resetSize() {
        width = 1.0
        height = 1.0
    }
}
  1. 调用协议方法:
var rect = Rectangle(width: 2.0, height: 3.0)
rect.resize(to: 5.0) // 成功调整
rect.resetSize()     // 重置为默认大小

协议作为类型使用

  1. 将协议用作变量、常量或参数的类型
func printDescription(of item: Describable) {
    print(item.description)
}

let person = Person(name: "李四", age: 30)
let car = Car(brand: "Toyota", model: "Camry")

printDescription(of: person) // 正常调用
printDescription(of: car)    // 同样正常调用
  1. 创建协议类型的数组
let items: [Describable] = [person, car]
for item in items {
    print(item.description)
}

协议继承与组合

  1. 定义一个新协议继承已有协议
protocol AdvancedDescribable: Describable {
    var detailedInfo: String { get }
}

任何遵循 AdvancedDescribable 的类型,必须同时满足 DescribabledetailedInfo 的要求。

  1. 实现继承后的协议
struct Product: AdvancedDescribable {
    let name: String
    let price: Double

    var description: String {
        return "商品:\(name)"
    }

    var detailedInfo: String {
        return "名称:\(name),价格:¥\(price)"
    }
}
  1. 组合多个协议(使用 &
func handleItem(_ item: Describable & Resizable) {
    print(item.description)
    _ = item.resize(to: 10.0)
}

只有同时遵循 DescribableResizable 的类型才能传入此函数。


可选协议要求(仅限 Objective-C 兼容)

  1. 在协议前加上 @objc 并标记方法为 optional(仅适用于类,且需继承自 NSObject):
@objc protocol OptionalProtocol {
    @objc optional func doSomething()
    @objc optional var optionalValue: Int { get }
}
  1. 实现时可选择性提供
class MyClass: NSObject, OptionalProtocol {
    // 可以不实现 doSomething 或 optionalValue
}
  1. 调用时需用可选链
let obj = MyClass()
obj.doSomething?() // 安全调用

注意:除非需要与 Objective-C 交互,否则应避免使用可选协议,因为会牺牲类型安全。


协议扩展:提供默认实现

  1. 为协议添加默认行为
extension Describable {
    func log() {
        print("[LOG] \(description)")
    }
}
  1. 所有遵循 Describable 的类型自动获得 log() 方法
person.log() // 输出:[LOG] 姓名:李四,年龄:30
car.log()    // 输出:[LOG] Toyota Camry
  1. 类型仍可自定义覆盖默认实现
struct CustomThing: Describable {
    var description: String { "自定义" }

    func log() {
        print(">>> \(description)")
    }
}

检查类型是否遵循协议

  1. 使用 is 检查
if car is Describable {
    print("car 遵循 Describable")
}
  1. 使用 as? 安全转换
let unknown: Any = car
if let describable = unknown as? Describable {
    print(describable.description)
}
  1. 使用 as! 强制转换(仅在确定时使用)
let d = unknown as! Describable

协议与泛型结合

  1. 定义泛型函数,约束类型必须遵循某协议
func duplicate<T: Describable>(_ item: T) -> [T] {
    return [item, item]
}
  1. 调用时传入符合协议的类型
let people = duplicate(person) // 返回 [Person, Person]

常见错误与避坑指南

错误现象 原因 解决方法
编译报错 “Type does not conform to protocol” 未实现协议要求的属性或方法 检查协议定义,补全缺失的实现
结构体中修改属性的方法未加 mutating 值类型方法默认不能修改自身 在方法前添加 mutating 关键字
协议方法调用崩溃 使用了 @objc optional 但未检查是否存在 使用 ? 可选调用,如 obj.method?()
无法将协议用于泛型约束 协议包含关联类型(如 Selfassociatedtype 改用泛型约束或具体类型

最佳实践

  1. 优先使用协议而非基类:Swift 推崇“面向协议编程”,比类继承更灵活。
  2. 协议命名用形容词:如 EquatableComparableCustomStringConvertible,而不是名词。
  3. 小而专注:一个协议只做一件事,便于组合复用。
  4. 通过扩展提供默认实现:减少重复代码,同时保留自定义能力。
  5. 避免过度设计:不要为了“看起来高级”而滥用协议,确保有实际收益。

评论 (0)

暂无评论,快来抢沙发吧!

扫一扫,手机查看

扫描上方二维码,在手机上查看本文