返回

Swift 之被忽视的角落:协议方法的静态派发与动态派发

IOS

协议方法的静态派发与动态派发

静态派发

静态派发是在编译时确定方法的实现。这意味着编译器可以根据调用方法的对象的类型来确定要调用的方法的实现。静态派发通常用于那些不需要在运行时改变行为的方法,例如计算一个对象的面积或周长。

动态派发

动态派发是在运行时确定方法的实现。这意味着编译器无法在编译时确定要调用的方法的实现,而是需要在运行时根据调用方法的对象的类型来确定。动态派发通常用于那些需要在运行时改变行为的方法,例如处理用户输入或与网络服务通信。

协议方法的派发方式

协议方法的派发方式根据协议的声明方式而有所不同。如果协议使用 class 声明,则其方法将被静态派发。如果协议使用 protocol 关键字声明,则其方法将被动态派发。

示例

为了更好地理解协议方法的静态派发和动态派发之间的区别,我们来看一个示例。假设我们有一个 Shape 协议,它定义了两个方法:area()perimeter()

protocol Shape {
    func area() -> Double
    func perimeter() -> Double
}

现在,我们有两个类 CircleSquare,它们都遵循 Shape 协议。

class Circle: Shape {
    var radius: Double

    init(radius: Double) {
        self.radius = radius
    }

    func area() -> Double {
        return Double.pi * radius * radius
    }

    func perimeter() -> Double {
        return 2 * Double.pi * radius
    }
}

class Square: Shape {
    var sideLength: Double

    init(sideLength: Double) {
        self.sideLength = sideLength
    }

    func area() -> Double {
        return sideLength * sideLength
    }

    func perimeter() -> Double {
        return 4 * sideLength
    }
}

现在,我们创建一个 Shape 数组,并向其中添加一个 Circle 对象和一个 Square 对象。

var shapes: [Shape] = []
shapes.append(Circle(radius: 5.0))
shapes.append(Square(sideLength: 10.0))

现在,我们可以使用一个 for 循环来遍历 shapes 数组,并调用每个对象的 area()perimeter() 方法。

for shape in shapes {
    print("Area: \(shape.area())")
    print("Perimeter: \(shape.perimeter())")
}

输出:

Area: 78.53981633974483
Perimeter: 31.41592653589793
Area: 100.0
Perimeter: 40.0

在这个示例中,area()perimeter() 方法都被动态派发。这意味着编译器无法在编译时确定要调用的方法的实现,而是需要在运行时根据调用方法的对象的类型来确定。

总结

协议方法的派发方式根据协议的声明方式而有所不同。如果协议使用 class 关键字声明,则其方法将被静态派发。如果协议使用 protocol 关键字声明,则其方法将被动态派发。

静态派发通常用于那些不需要在运行时改变行为的方法,例如计算一个对象的面积或周长。动态派发通常用于那些需要在运行时改变行为的方法,例如处理用户输入或与网络服务通信。