# 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)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ryukiedev.gitbook.io/wiki/swift/protocol-yu-jing-tai-pai-fa-dong-tai-pai-fa.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
