本小节通过性能消耗的Demo来从底层讲了协议底层容器
相关的知识点
先看demo
///使用泛型参数的方法--性能高
func f<C: CustomStringConvertible>(_ x: C) -> Int {
return MemoryLayout.size(ofValue: x)
}
///使用协议做参数的方法--性能低
func g(_ x: CustomStringConvertible) -> Int {
return MemoryLayout.size(ofValue: x)
}
f(5) // 8--正常一个Int类型在64位中Int的尺寸
g(5) // 40
明明是同一个Int为嘛后面的方法size就大很多。
我们先看看g(5) 值为 40 是怎么组成的,这里面存在一个不透明的容器
的概念(下图中标注的有)。
40的长度是由三部分组成
1.存储值的缓冲区(3个指针长度) 3 * 8 = 24
2.元数据 8
3.目击表(vtable 可以有0个或者多个 这里有1个) 8
目击表是让动态派发
成为可能的关键,为一个特定的类型将协议的实现
进行编码,表中会包含一个指向特定类型中的实现的入口
。
OC中的协议不需要封装在存在容器中,so~
MemoryLayout.size // 8
不推荐❎
//隐式打包
func printProtocol(array: [CustomStringConvertible]) {
print(array)
}
推荐✅ swift标准库
中大多数使用场景。
//没有打包
func printGeneric<A: CustomStringConvertible>(array: [A]) {
print(array)
}