关于Swift协议的基础知识和高级内容,包括:
- 协议的基本语法和定义
- 协议的遵循
- 协议中添加属性
- 协议中定义方法(实例方法、类方法、异变方法)
- 协议中定义初始化方法
- 协议扩展
- 与OC的交互
- 协议的方法调度机制
- 协议的内存结构和底层实现
涵盖:
- 协议作为类型使用的各种方式
- 协议继承
- 协议组合
- 协议作为泛型约束
- 协议与扩展的结合使用
- 协议的关联类型
- Self 类型
- 协议的一致性检查
- 协议用于实现设计模式
- 常见的Swift标准库中的协议实例
协议是Swift中极其强大且灵活的特性,它可以定义方法、属性和其他特定任务或功能的蓝图。以下是Swift协议的全面应用场景和详细介绍。
一、协议的基本用法
1. 定义协议
协议定义了一个蓝图,声明遵循者必须实现的属性和方法。
swift
protocol Vehicle {
// 属性要求
var numberOfWheels: Int { get }
var description: String { get }
// 方法要求
func makeNoise()
}
2. 遵循协议
类、结构体和枚举都可以遵循协议:
swift
// 结构体遵循协议
struct Bicycle: Vehicle {
var numberOfWheels: Int = 2
var description: String {
return "一辆有\(numberOfWheels)个轮子的自行车"
}
func makeNoise() {
print("叮叮叮!")
}
}
// 类遵循协议
class Car: Vehicle {
var numberOfWheels: Int = 4
var description: String {
return "一辆有\(numberOfWheels)个轮子的汽车"
}
func makeNoise() {
print("喇叭声!")
}
}
// 枚举遵循协议
enum TransportOption: Vehicle {
case airplane, helicopter, boat
var numberOfWheels: Int {
switch self {
case .airplane: return 3
case .helicopter: return 0
case .boat: return 0
}
}
var description: String {
switch self {
case .airplane: return "飞机"
case .helicopter: return "直升机"
case .boat: return "船"
}
}
func makeNoise() {
switch self {
case .airplane: print("轰轰轰!")
case .helicopter: print("噗噗噗!")
case .boat: print("隆隆隆!")
}
}
}
二、协议作为类型
1. 协议类型的变量和常量
协议可以像普通类型一样使用:
swift
let bicycle: Vehicle = Bicycle()
let car: Vehicle = Car()
let transport: Vehicle = TransportOption.boat
// 使用协议类型的数组
let vehicles: [Vehicle] = [bicycle, car, transport]
for vehicle in vehicles {
print("描述: \(vehicle.description)")
vehicle.makeNoise()
}
2. 协议类型作为函数参数
swift
func printVehicleDetails(vehicle: Vehicle) {
print("这是\(vehicle.description),有\(vehicle.numberOfWheels)个轮子")
vehicle.makeNoise()
}
printVehicleDetails(vehicle: bicycle)
3. 协议类型作为返回值
swift
func createRandomVehicle() -> Vehicle {
let random = Int.random(in: 0...2)
switch random {
case 0: return Bicycle()
case 1: return Car()
default: return TransportOption.airplane
}
}
let randomVehicle = createRandomVehicle()
三、协议的属性要求
1. 可读属性和可读写属性
swift
protocol ReadableProtocol {
var readableProperty: String { get } // 只读属性
}
protocol WritableProtocol {
var writableProperty: String { get set } // 可读写属性
}
struct MyStruct: ReadableProtocol, WritableProtocol {
// 只读属性可以用计算属性或存储属性实现
var readableProperty: String {
return "只能读取"
}
// 可读写属性必须是变量存储属性或get/set计算属性
var writableProperty: String = "可以读取和修改"
}
2. 类型属性要求
swift
protocol ClassProtocol {
static var typeProperty: Int { get set }
static func typeMethod()
}
class MyClass: ClassProtocol {
static var typeProperty: Int = 10
static func typeMethod() {
print("类型方法被调用")
}
}
四、协议的方法要求
1. 实例方法
swift
protocol TaskProtocol {
func executeTask()
func calculateTime() -> TimeInterval
}
class Task: TaskProtocol {
func executeTask() {
print("执行任务")
}
func calculateTime() -> TimeInterval {
return 2.5
}
}
2. 异变方法(mutating)
允许在值类型(结构体/枚举)中修改实例:
swift
protocol Togglable {
mutating func toggle()
}
struct Switch: Togglable {
var isOn: Bool = false
mutating func toggle() {
isOn = !isOn
}
}
enum Theme: Togglable {
case light, dark
mutating func toggle() {
switch self {
case .light: self = .dark
case .dark: self = .light
}
}
}
3. 带默认参数的方法
协议方法定义中不能有默认参数值,但在实现时可以添加:
swift
protocol Greetable {
func greet(name: String)
}
struct Person: Greetable {
// 实现时可以提供默认参数
func greet(name: String = "朋友") {
print("你好,\(name)!")
}
}
let person = Person()
person.greet() // 使用默认参数: "你好,朋友!"
person.greet(name: "小明") // "你好,小明!"
五、协议的初始化器要求
1. 基本初始化器
swift
protocol Initializable {
init(value: Int)
}
class InitializableClass: Initializable {
var value: Int
// 遵循协议的类必须使用required关键字
required init(value: Int) {
self.value = value
}
}
struct InitializableStruct: Initializable {
var value: Int
// 结构体不需要required关键字
init(value: Int) {
self.value = value
}
}
2. 带继承的初始化器
swift
class SuperClass {
init() {
print("SuperClass初始化")
}
}
class SubClass: SuperClass, Initializable {
var storedValue: Int
// 需要同时标记required和override
required override init(value: Int) {
self.storedValue = value
super.init()
}
}
3. 可失败初始化器
swift
protocol SafeInitializable {
init?(safeValue: String)
}
struct SafeNumber: SafeInitializable {
var number: Int
init?(safeValue: String) {
guard let number = Int(safeValue) else {
return nil
}
self.number = number
}
}
let validNumber = SafeNumber(safeValue: "123") // 成功初始化
let invalidNumber = SafeNumber(safeValue: "abc") // 返回nil
六、协议的继承
协议可以继承一个或多个其他协议:
swift
protocol Named {
var name: String { get }
}
protocol Aged {
var age: Int { get }
}
// PersonProtocol继承了Named和Aged协议
protocol PersonProtocol: Named, Aged {
var email: String { get set }
}
struct Employee: PersonProtocol {
// 实现Named协议要求
var name: String
// 实现Aged协议要求
var age: Int
// 实现PersonProtocol要求
var email: String
}
七、协议组合
1. 使用&运算符组合多个协议
swift
func wishHappyBirthday(to celebrator: Named & Aged) {
print("祝\(celebrator.name),\(celebrator.age)岁生日快乐!")
}
let john = Employee(name: "John", age: 30, email: "[email protected]")
wishHappyBirthday(to: john)
2. 组合协议与类要求
swift
class Person {
var firstName: String
var lastName: String
init(firstName: String, lastName: String) {
self.firstName = firstName
self.lastName = lastName
}
}
protocol FullyNamed {
var fullName: String { get }
}
// 要求同时为Person类型并遵循FullyNamed协议
func printFullNameOfPerson(person: Person & FullyNamed) {
print("全名: \(person.fullName)")
}
class Student: Person, FullyNamed {
var grade: Int
init(firstName: String, lastName: String, grade: Int) {
self.grade = grade
super.init(firstName: firstName, lastName: lastName)
}
var fullName: String {
return "\(firstName) \(lastName)"
}
}
let student = Student(firstName: "李", lastName: "明", grade: 3)
printFullNameOfPerson(person: student)
八、协议扩展
1. 为协议添加默认实现
swift
protocol TextRepresentable {
var textDescription: String { get }
}
// 提供默认实现
extension TextRepresentable {
var textDescription: String {
return "这是一个TextRepresentable类型"
}
}
// 可以使用默认实现
struct SimpleStruct: TextRepresentable {
// 不需要实现textDescription,将使用默认实现
}
// 可以提供自定义实现
struct DetailedStruct: TextRepresentable {
var textDescription: String {
return "这是一个详细描述"
}
}
let simple = SimpleStruct()
print(simple.textDescription) // "这是一个TextRepresentable类型"
let detailed = DetailedStruct()
print(detailed.textDescription) // "这是一个详细描述"
2. 有条件的协议扩展
可以只对满足特定条件的类型提供扩展:
swift
// 只为Collection协议扩展,且其元素是TextRepresentable的
extension Collection where Element: TextRepresentable {
var allTextDescriptions: String {
return self.map { $0.textDescription }.joined(separator: ", ")
}
}
let textItems: [TextRepresentable] = [SimpleStruct(), DetailedStruct()]
print(textItems.allTextDescriptions)
3. 扩展协议添加更多功能
swift
protocol Identifiable {
var id: String { get }
}
extension Identifiable {
// 添加默认实现
var id: String {
return UUID().uuidString
}
// 添加新方法
func identify() {
print("ID: \(id)")
}
}
struct User: Identifiable {
// 可选择是否重写id
}
let user = User()
user.identify() // 使用扩展中添加的方法
九、泛型与协议
1. 协议作为泛型约束
swift
// T必须遵循Equatable协议
func findIndex<T: Equatable>(of valueToFind: T, in array: [T]) -> Int? {
for (index, value) in array.enumerated() {
if value == valueToFind {
return index
}
}
return nil
}
let numbers = [1, 2, 3, 4, 5]
if let index = findIndex(of: 3, in: numbers) {
print("找到3在位置: \(index)")
}
2. 关联类型(Associated Types)
协议中可以定义关联类型,这是一个占位名:
swift
protocol Container {
// 定义一个关联类型Item
associatedtype Item
// 使用关联类型的方法
mutating func add(_ item: Item)
var count: Int { get }
subscript(i: Int) -> Item { get }
}
// Array实现Container协议
extension Array: Container {
// Swift自动推断Item为Element类型
mutating func add(_ item: Element) {
self.append(item)
}
// count和subscript已经存在于Array中
}
var numbers = [1, 2, 3]
numbers.add(4)
print(numbers.count) // 4
print(numbers[2]) // 3
3. 约束关联类型
swift
protocol SortableContainer: Container where Item: Comparable {
func sorted() -> [Item]
}
extension Array: SortableContainer where Element: Comparable {
func sorted() -> [Element] {
return self.sorted()
}
}
let names = ["Tom", "Alex", "John"]
let sortedNames = names.sorted() // ["Alex", "John", "Tom"]
十、协议的一致性检查
1. is运算符
检查实例是否遵循特定协议:
swift
protocol Flyable {
func fly()
}
struct Bird: Flyable {
func fly() {
print("鸟在飞!")
}
}
let object: Any = Bird()
if object is Flyable {
print("这个对象可以飞行")
}
2. as?和as!运算符
尝试将实例转换为特定协议类型:
swift
if let flyingObject = object as? Flyable {
flyingObject.fly() // 调用协议方法
}
十一、使用协议实现设计模式
1. 代理模式
swift
// 定义代理协议
protocol TaskDelegate: AnyObject {
func taskDidStart(_ task: TaskManager)
func taskDidComplete(_ task: TaskManager)
func task(_ task: TaskManager, didFailWithError error: Error)
}
class TaskManager {
weak var delegate: TaskDelegate?
func startTask() {
delegate?.taskDidStart(self)
// 任务实现...
delegate?.taskDidComplete(self)
}
func handleError(_ error: Error) {
delegate?.task(self, didFailWithError: error)
}
}
class TaskViewController: UIViewController, TaskDelegate {
let taskManager = TaskManager()
override func viewDidLoad() {
super.viewDidLoad()
taskManager.delegate = self
}
func startOperation() {
taskManager.startTask()
}
// TaskDelegate方法实现
func taskDidStart(_ task: TaskManager) {
print("任务开始")
}
func taskDidComplete(_ task: TaskManager) {
print("任务完成")
}
func task(_ task: TaskManager, didFailWithError error: Error) {
print("任务失败: \(error.localizedDescription)")
}
}
2. 策略模式
swift
protocol SortingStrategy {
func sort<T: Comparable>(_ items: [T]) -> [T]
}
struct QuickSort: SortingStrategy {
func sort<T: Comparable>(_ items: [T]) -> [T] {
// 实现快速排序...
return items.sorted()
}
}
struct MergeSort: SortingStrategy {
func sort<T: Comparable>(_ items: [T]) -> [T] {
// 实现归并排序...
return items.sorted()
}
}
class SortContext {
private var strategy: SortingStrategy
init(strategy: SortingStrategy) {
self.strategy = strategy
}
func setStrategy(_ strategy: SortingStrategy) {
self.strategy = strategy
}
func executeSort<T: Comparable>(_ items: [T]) -> [T] {
return strategy.sort(items)
}
}
// 使用
let sortContext = SortContext(strategy: QuickSort())
var result = sortContext.executeSort([3, 1, 4, 1, 5, 9])
// 切换策略
sortContext.setStrategy(MergeSort())
result = sortContext.executeSort([3, 1, 4, 1, 5, 9])
十二、Self要求
1. 使用Self表示遵循者类型
swift
protocol Copyable {
// Self代表遵循此协议的具体类型
func copy() -> Self
}
struct Point: Copyable {
var x: Int
var y: Int
func copy() -> Self {
return Point(x: self.x, y: self.y)
}
}
class Document: Copyable {
var title: String
var content: String
init(title: String, content: String) {
self.title = title
self.content = content
}
func copy() -> Self {
// 需要创建正确的Self类型,这里用了类型转换
let copy = type(of: self).init(title: title, content: content)
return copy
}
// 为了支持上面的init方法,需要添加required初始化器
required init(title: String, content: String) {
self.title = title
self.content = content
}
}
2. 静态成员中的Self
swift
protocol Factory {
static func create() -> Self
}
struct ProductA: Factory {
static func create() -> Self {
return ProductA()
}
}
let product = ProductA.create()
十三、与Objective-C交互的协议
1. @objc协议
swift
// 只能被类采纳的协议
@objc protocol DataSourceDelegate {
// 必须实现的方法
func numberOfItems() -> Int
// 可选实现的方法
@objc optional func itemAt(index: Int) -> Any?
}
class DataProvider: NSObject, DataSourceDelegate {
func numberOfItems() -> Int {
return 10
}
// 可选方法,不是必须实现的
}
let provider = DataProvider()
print(provider.numberOfItems()) // 10
2. 继承NSObjectProtocol
swift
class CustomView: UIView, NSObjectProtocol {
// NSObjectProtocol方法已通过UIView继承的NSObject实现
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
}
十四、协议的性能优化
1. 协议默认实现中的static分派
swift
protocol Drawable {
func draw()
}
extension Drawable {
func draw() {
print("默认绘制实现")
}
// 添加未在协议中声明的方法使用静态分派
func prepare() {
print("准备绘制")
}
}
struct Canvas: Drawable {
// 使用自定义实现代替默认实现
func draw() {
print("Canvas绘制实现")
}
// 重写未在协议中声明的方法
func prepare() {
print("Canvas准备")
}
}
let shape: Drawable = Canvas()
shape.draw() // "Canvas绘制实现" - 动态分派
shape.prepare() // "准备绘制" - 静态分派,而不是"Canvas准备"
2. 使用final关键字优化
swift
final class OptimizedDrawing: Drawable {
func draw() {
print("优化的绘制")
}
}
十五、协议的内存模型
如前面文章中所述,Swift协议在内存上通过存在容器(Existential Container)和协议见证表(Protocol Witness Table)实现,具体分为:
- 小值类型直接存储在容器的Value Buffer中
- 大值类型在堆上分配内存,采用写时复制优化
- 引用类型存储实例的堆地址
swift
// 1. 小值类型示例
protocol SmallValueProtocol {
var value: Int { get }
}
struct SmallValue: SmallValueProtocol {
var value: Int
}
// 2. 大值类型示例
protocol LargeValueProtocol {
var values: [Int] { get }
}
struct LargeValue: LargeValueProtocol {
var values: [Int] // 数组在堆上管理
}
// 3. 引用类型示例
protocol ReferenceProtocol {
var id: Int { get }
}
class Reference: ReferenceProtocol {
var id: Int
init(id: Int) {
self.id = id
}
}
十六、常见的标准库协议
1. Equatable
swift
struct Point: Equatable {
var x: Int
var y: Int
// 自动合成的==运算符实现
// static func == (lhs: Point, rhs: Point) -> Bool {
// return lhs.x == rhs.x && lhs.y == rhs.y
// }
}
let p1 = Point(x: 1, y: 2)
let p2 = Point(x: 1, y: 2)
print(p1 == p2) // true
2. Comparable
swift
struct Person: Comparable {
var name: String
var age: Int
static func < (lhs: Person, rhs: Person) -> Bool {
return lhs.age < rhs.age
}
static func == (lhs: Person, rhs: Person) -> Bool {
return lhs.age == rhs.age
}
}
let people = [
Person(name: "张三", age: 30),
Person(name: "李四", age: 25),
Person(name: "王五", age: 40)
]
let sortedPeople = people.sorted()
// 排序后: 李四(25), 张三(30), 王五(40)
3. Hashable
swift
struct Product: Hashable {
var id: Int
var name: String
// 自动合成hash(into:)方法
// func hash(into hasher: inout Hasher) {
// hasher.combine(id)
// hasher.combine(name)
// }
}
let products = [
Product(id: 1, name: "iPhone"),
Product(id: 2, name: "iPad"),
Product(id: 3, name: "MacBook")
]
let productSet = Set(products)
let productDict = Dictionary(uniqueKeysWithValues: products.map { ($0, $0.id) })
4. Codable (Encodable & Decodable)
swift
struct User: Codable {
var id: Int
var name: String
var email: String
}
// 编码
let user = User(id: 1, name: "张三", age: "[email protected]")
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
do {
let data = try encoder.encode(user)
if let json = String(data: data, encoding: .utf8) {
print(json)
}
} catch {
print("编码失败: \(error)")
}
// 解码
let jsonString = """
{
"id": 2,
"name": "李四",
"email": "[email protected]"
}
"""
if let jsonData = jsonString.data(using: .utf8) {
let decoder = JSONDecoder()
do {
let decodedUser = try decoder.decode(User.self, from: jsonData)
print("解码用户: \(decodedUser.name)")
} catch {
print("解码失败: \(error)")
}
}
5. CustomStringConvertible
swift
struct Book: CustomStringConvertible {
var title: String
var author: String
var year: Int
var description: String {
return "\(title) by \(author) (\(year))"
}
}
let book = Book(title: "Swift编程", author: "苹果", year: 2023)
print(book) // "Swift编程 by 苹果 (2023)"
十七、总结
Swift的协议是一种极其强大的抽象机制,可以用于:
- 定义接口和契约
- 实现多态性
- 组织代码和分离关注点
- 提供默认实现
- 实现各种设计模式
- 支持泛型编程
- 在不同类型间共享行为
通过合理使用协议,可以创建更灵活、可扩展且可复用的代码,这也是Swift语言的核心设计理念之一。
Swift协议有三种方法调度方式:
- 静态派发(结构体方法、未在协议中声明的扩展方法)
- 表派发(通过witness_table,协议中声明的方法)
- 消息派发(使用@objc dynamic标记的方法)
理解这些调度机制有助于编写更高效的Swift代码。