Swift-协议(protocol)

261 阅读4分钟

协议

协议定义了一组方法、属性或其他要求,用于指定 遵循该协议的类型 所需实现的功能。

协议可以声明:方法、属性、下标

可以被结构体、类、枚举遵守,多个协议之间用逗号隔开。

1.声明协议

关键字protocol

protocol SomeProtocol {

    var id: Int { get set } 
    var token: String { get }    

    func someMethod()                
    
    init(parameter: String)     
}

在协议内部,列出所需的所有方法,这些方法内部不包含具体实现。

定义 类型方法、类型属性、类型下标,必须用static

  • 协议属性

协议中定义属性时,必须用var

实现协议时的属性权限,要不小于协议中定义的属性权限

协议定义get、set,用var存储属性或get、set计算属性去实现

协议定义get,用任何属性都可以实现

-

  • 初始化器

协议的init

协议中还可以定义 init。非final类实现时必须加上required

protocol Drawable {
    init(x: Int, y: Int)
}
class Point : Drawable {
    required init(x: Int, y: Int) { }
}
final class Size : Drawable {
    init(x: Int, y: Int) { }
}

如果从协议实现的初始化器,刚好是重写了父类的指定初始化器,那么这个初始化必须同时加required、override

// 协议
protocol Livable {
    init(age: Int)
}
// 父类
class Person {
    init(age: Int) { }
}

class Student : Person, Livable {
    required override init(age: Int) {
        super.init(age: age)
    }
}
  • init、init?、init! 协议中定义的init?、init!,可以用init、init?、init! 去实现。 协议中定义的init,可以用init、init!去实现
 protocol Livable {
    init()
    init?(age: Int)
    init!(no: Int)
}

class Person : Livable {
    required init() { }
    // required init!() { }
    required init?(age: Int) { }
    // required init!(age: Int) { }
    // required init(age: Int) { }
    required init!(no: Int) { }
    // required init?(no: Int) { }
    // required init(no: Int) { }
}

2.遵守协议

结构体、类或枚举,都可以遵守协议,来实现该协议的所有方法。

struct MyStruct: SomeProtocol {

    var someProperty: Int
    
    func someMethod() {
        print("Implemented")
    }
    
    init(someParameter: String) {
        self.someProperty = someParameter.count
    }
}

协议一般没有指定 类型的全部功能,仅指定了最低限度的功能。您可以根据需要为类型添加其他属性和方法。

遵守协议的类、结构体或枚举,必须实现协议方法的 具体内容

那么,协议有什么特殊作用?——它允许我们使用 协议 作为参数的类型。

func printInfo(_ value: SomeProtocol) {
    value.someMethod()
}

因此,协议让我们只关注我们想要使用的功能类型,而不关注确切的类型。

3.为什么 Swift 需要协议?

协议可以让我们定义 结构体、类和枚举应该如何工作:应该具有什么方法、属性。

Swift 将为我们强制执行这些规则,因此,当我们说某个类型符合协议时,Swift 将确保它一定具有该协议所需的所有方法和属性。

在实践中,协议允许我们以更通用的方式 处理我们的数据。

4.协议的继承

协议可以继承其他协议,实现功能的叠加。

5.协议合成 &

protocol A { }
protocol B { }

func printIt(value: A & B) { }

表示传入的值必须同时遵守协议 A 和 B。

6.类限定协议

使用 AnyObject 限定只有类 能遵守此协议,常用于 delegate 模式。

protocol MyDelegate: AnyObject {
    func didSomething()
}

7.可选协议方法

只能被 class 遵守,只能用于 @objc 的协议(兼容 Objective-C)

@objc protocol MyObjCDelegate {
    @objc optional func optionalMethod()
}

协议扩展

Swift 允许为协议提供默认实现,通过 extension 扩展协议。这是 Swift 面向协议编程(POP)的核心特性。

协议中定义方法时,不能有默认参数值。 默认情况下,协议中定义的内容必须全部都实现

用途:

  • 提供默认实现

这让我们不需要在许多结构和类之间,复制该功能。

  • 添加通用方法(即使协议没有声明)
  • 避免重复代码
  • 构建功能模块
protocol Greetable {
    func greet()
}

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

这样,遵循者即使没有实现协议方法,也能直接调用。若遵循者实现了需要方法,则会覆盖。

类扩展 只影响某个具体类型; 协议扩展 影响所有遵循该协议的类型

使用场景

  • 委托模式

  • 数据源模式(DataSource)

  • ViewModel/Service 通用接口

  • 泛型+协议约束组合

func printAll<T: CustomStringConvertible>(_ items: [T]) {
    for item in items {
        print(item.description)
    }
}