> For the complete documentation index, see [llms.txt](https://ryukiedev.gitbook.io/wiki/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ryukiedev.gitbook.io/wiki/swift/protocol-yu-jing-tai-pai-fa-dong-tai-pai-fa.md).

# 19.Protocol与静态派发、动态派发

### 一、 场景一

***我们定义这样一个\*\*\*\*`Protocol`***

```swift
protocol DescriptionProtocol {
    var name: String { get }
}
```

***添加拓展方法\*\*\*\* \*\*\*\*`printDescription`***

```swift
extension DescriptionProtocol {
    func printDescription() {
        print("我是：\(name)")
    }
}
```

***新建类\*\*\*\* ****`Apple`**** ****遵循协议**** \*\*\*\*`DescriptionProtocol`***

```swift
class Apple: DescriptionProtocol {
    var name: String {
        return "苹果"
    }

    func printDescription() {
        print("\(name)好好吃啊！")
    }
}
```

***新建类\*\*\*\* ****`People`**** ****遵循协议**** \*\*\*\*`DescriptionProtocol`***

```swift
class People: DescriptionProtocol {
    var name: String {
        return "人类"
    }

    func printDescription() {
        print("\(name)真有意思！")
    }
}
```

***分别创建实例对象***

```swift
let aApple = Apple()
let aPeople = People()

aApple.printDescription()
aPeople.printDescription()
```

### 1.1 思考

```swift
🤔思考一下会输出什么呢？














// 这里是调用了Class内实现的方法，而没有调用protocol的拓展实现
aApple.printDescription() // 苹果好好吃啊！
aPeople.printDescription() // 人类真有意思！
```

### 1.2 再通过这样的方法来调用：

```swift
func showDescription(of: DescriptionProtocol) {
    of.printDescription()
}

showDescription(of: aApple)
showDescription(of: aPeople)
```

```swift
🤔思考一下会输出什么呢？
















showDescription(of: aApple) // 我是：苹果
showDescription(of: aPeople) // 我是：人类
```

是不是感觉很奇怪？

* `aApple.printDescription()`
  * 这种方式直接调用了类定义的实例方法，而不是协议中实现的方法，是动态派发的
* `showDescription`
  * 中调用的是Protocol中实现的函数，是静态派发
* `printDescription`在协议中和类中虽然同名，但却是毫不相干的函数，存储的区域也各不相同

## 二、 场景二

***我们将函数在协议中声明一下下，又会有什么结果呢？***

```swift
protocol DescriptionProtocol {
    var name: String { get }
    func printDescription()
}
```

结果：

```swift
苹果好好吃啊！
人类真有意思！
苹果好好吃啊！
人类真有意思！
```

* `aApple.printDescription()`
  * 和场景一是一样的，是动态派发
* `showDescription`
  * 调用了协议中声明的函数，是动态派发

## 三、 总结

由继承而得到的多态表现，本质上是把所有的方法的实现都放在一张`表`里，每次调用都必须先在表中查询，可以称之为`动态调用`。 因此才有了`覆写`的概念：方法被覆写，即当子类调用该方法时，会使用子类的实现而非父类的。

而协议与类有所不同。协议所定义的方法，也和类一样，是`动态调用`的；但那些未出现在定义中，而仅出现于 `Extension` 中的方法是`静态调用`的，即这个方法属于协议，不属于协议的遵从者。

性能上也是`静态`优于`动态`。像是一些高频调用的函数我们可以通过静态的方式来做提高效率。`动态调用`虽然步骤会多一些，比如OC的消息转发机制，但是充满灵活性，在业务开发中会经常用到。

## 参考

> [static-vs-dynamic-dispatch-in-swift](https://medium.com/flawless-app-stories/static-vs-dynamic-dispatch-in-swift-a-decisive-choice-cece1e872d)
