编译型语言有三种基础的派发方式: 静态派发;函数表派发;消息机制派发(动态派发).
我们都知道Objective-C是使用的消息机制派发,任何的方法调用都会转为为Objc_msgSend... 这是调用函数最动态的方式..这方派发方式的特点是开发者可以在运行时改变函数的行为.不止可以通过Method_swizzing来改变,甚至可以用isa-swizzing修改对象的继承关系,可以实现自定义派发.
消息机制派发这种非常动态的特性也会造成一些问题和它本身难以避免的问题.(例如不易于维护,可读性和性能等问题)
Swift作为比较年轻的高级语言,它会根据许多因素,在不同的地方选择不同的派发方式.并且随着Swift的版本也在优化更新它的派发方式.
- 声明的位置
- 引用类型
- 具体行为
- 显示标识符
最显然的就是在Swift中创建NSObject类,使用Runtime的方法,那必然这些函数是动态派发的..还有一些标注了dynamic的函数或者属性,他们都会使用消息机制.
我们在开发中当然没有必要完全知道自己编写的每一个函数到底是什么样的方式派发.但我们需要留意因为派发方式的不同可能会造成的问题.比如下面这个例子:
class Dog: NSObject {
var name = ""
static func ==(lhs: Dog, rhs: Dog) -> Bool {
return lhs.name == rhs.name
}
}
声明一个 Dog的类,并实现它的 "=="运算符,用来比较两个Dog的name属性是否一致.
let dog1 = Dog()
let dog2 = Dog()
print(dog1 == dog2) // true
这两个dog 的name都为"" ,所以 == 运算符返回true.
但如果我们修改一下代码.
let dog1: NSObject = Dog()
let dog2 = Dog()
print(dog1 == dog2) // false
将dog1声明为NSObject, 我们发现 dog1与dog2比较的时候并没有走在Dog中声明的== 方法, 它调用的是NSObject中的==方法,.如果你不留意Swift中静态派发的行为...这可能和你预想的大有不同..
Swift并没有在运行时检查dog1的具体类型调用它本身的 == 方法.而是在编译阶段就决定了要调用类型NSObject的 == 方法.
详细的关于函数派发的资料参考: 参考