返回

Swift 独孤九剑:八、协议的本质大揭秘

IOS

协议的本质

在 Swift 中,协议是一种类似于接口的机制,它定义了一组方法、属性和要求,这些方法、属性和要求可以被其他类型采用。协议可以被看作是一种契约,它规定了采用该协议的类型必须实现哪些方法和属性。

协议在 Swift 中有两种主要类型:

  • 命名协议 :使用 protocol 定义,可以被其他类型采用。
  • 匿名协议 :使用 @objc protocol 关键字定义,只能被 Objective-C 类型采用。

协议的实现

当一个类型采用了一个协议时,它必须实现协议中定义的所有方法和属性。这些方法和属性可以在类型本身中实现,也可以在类型扩展中实现。

例如,我们可以定义一个名为 Drawable 的协议,其中定义了一个名为 draw() 的方法:

protocol Drawable {
    func draw()
}

我们可以通过在类型中实现 draw() 方法来让该类型采用 Drawable 协议:

struct Circle: Drawable {
    func draw() {
        print("Drawing a circle")
    }
}

也可以通过在类型扩展中实现 draw() 方法来让该类型采用 Drawable 协议:

extension Square: Drawable {
    func draw() {
        print("Drawing a square")
    }
}

协议的运行时行为

在运行时,协议被实现为一种称为协议见证 (protocol witness) 的特殊数据结构。协议见证包含了协议中所有方法和属性的实现。

当一个类型采用了一个协议时,编译器会生成一个协议见证,该协议见证包含了该类型中所有方法和属性的实现。当该类型被实例化时,协议见证会被存储在实例中。

当调用一个协议方法时,编译器会查找该协议的协议见证,然后调用协议见证中相应的方法。

协议的编译期行为

在编译期,协议被用作一种类型检查机制。当一个类型采用了一个协议时,编译器会检查该类型是否实现了协议中定义的所有方法和属性。

如果该类型没有实现协议中定义的所有方法和属性,编译器将报告一个错误。

协议与其他编程语言中的接口

协议与其他编程语言中的接口非常相似。它们都定义了一组方法和属性,这些方法和属性可以被其他类型采用。

然而,协议与其他编程语言中的接口也有一个主要区别。在 Swift 中,协议可以被扩展。这意味着我们可以为一个协议添加新的方法和属性,而不必修改采用该协议的所有类型。

协议的应用场景

协议在 Swift 中有许多应用场景,包括:

  • 定义类型之间的公共接口 。例如,我们可以定义一个 Drawable 协议,其中定义了一个名为 draw() 的方法。然后,我们可以让任何想要绘制自己的图形的类型采用 Drawable 协议。
  • 创建可扩展的类型 。我们可以通过为协议添加新的方法和属性来扩展协议。这使得我们可以创建可扩展的类型,这些类型可以随着时间的推移而添加新的功能。
  • 实现多态性 。协议可以用于实现多态性。例如,我们可以定义一个 Drawable 协议,其中定义了一个名为 draw() 的方法。然后,我们可以将任何采用 Drawable 协议的类型存储在一个数组中。当我们调用 draw() 方法时,数组中的所有元素都会被绘制。

结论

协议是 Swift 中一种非常强大的机制,它可以用于定义类型之间的公共接口、创建可扩展的类型和实现多态性。理解协议的本质和用法将帮助我们编写更健壮、更优雅的代码。