多态
- OC 中是使用 runtime 完成的,通过找到 isa 指针进行消息发送
- Swift 中是使用类似 C++ 中的虚表
class Animal {
func speak() {
print("Animal speak")
}
func eat() {
print("Animal eat")
}
func sleep() {
print("Animal sleep")
}
}
class Dog: Animal {
override func speak() {
print("Dog speak")
}
override func eat() {
print("Dog eat")
}
func run() {
print("Dog run")
}
}
var anim: Animal
anim = Animal()
anim.speak()
anim.eat()
anim.sleep()
anim = Dog()
anim.speak()
anim.eat()
anim.sleep()
---------------------------执行结果---------------------------
Animal speak
Animal eat
Animal sleep
Dog speak
Dog eat
Animal sleep
Dog run
---------------------------汇编分析---------------------------
swiftstudy`test29():
callq 0x1000052e0
movq %rax, -0x30(%rbp)
movq -0x30(%rbp), %rcx
movq (%rcx), %rdx
movq 0x50(%rdx), %rdx // Animal.speak
callq *%rdx
movq 0x58(%rdx), %rdx // Animal.eat
callq *%rdx
思考
- class 调用方法和 struct 调用方法有什么不同?
struct Animal {
func speak() {
print("Animal speak")
}
func eat() {
print("Animal eat")
}
func sleep() {
print("Animal sleep")
}
}
var anim: Animal
anim = Animal()
anim.speak()
anim.eat()
anim.sleep()
---------------------------执行结果---------------------------
Animal speak
Animal eat
Animal sleep
---------------------------汇编分析---------------------------
callq 0x1000053a0 ; init() -> Animal #1 in swiftstudy.test30() -> () in Animal #1 in swiftstudy.test30() -> () at main.swift:511
callq 0x1000053b0 ; speak() -> () in Animal #1 in swiftstudy.test30() -> () at main.swift:512
callq 0x100005460 ; eat() -> () in Animal #1 in swiftstudy.test30() -> () at main.swift:515
callq 0x100005510 ; sleep() -> () in Animal #1 in swiftstudy.test30() -> () at main.swift:518
可以看出来就是直接调用,callq 一个函数地址
- 这个对象的类型信息存储在内存中的什么位置?
全局区。
初始化器
- 类、结构体、枚举都可以定义初始化器
- 类有2种初始化器
- 指定初始化器
- 便捷初始化器
- 每个类至少有一个指定初始化器,指定初始化器是类的主要初始化器
- 默认初始化器总是类的指定初始化器
- 类偏向于少量指定初始化器,一个类通常只有一个指定初始化器
- 初始化器的相互调用规则
- 指定初始化器必须 从它的直系父类调用指定初始化器
- 便捷初始化器必须从相同的类里调用另一个初始化器
- 便捷初始化器最终必须调用一个指定初始化器
初始化器的相互调用
两段式初始化
- 看到别人有整理好了的: Swift --- 初始化器相关(Initialize)
- 第一阶段:初始化所有存储属性
- 外层调用指定/便捷初始化器
- 分配内存给实力,但未初始化
- 指定初始化器确保当前类定义的存储属性都初始化
- 指定初始化器调用父类的初始化器,不断向上调用,形成初始化器链
- 第二阶段:设置新的存储属性值
- 从顶部初始化器往下,链中的每一个指定初始化器都会有机会进一步定制实例
- 初始化器现在能够使用self(访问、修改它的属性,调用它的实例方法等等)
- 最终,链中任何便捷初始化器都有机会定制实例以及使用self
- 安全检查
- 指定初始化器必须保证在调用父类初初始化器之前,其所在类定义的所有存储属性都要初始化完成
- 指定初始化器必须先调用父类初始化器,然后才能为继承的属性设置新值
- 便捷初始化器必须先调用同类中的其它初始化器,然后再为任意属性设置新值
- 初始化器在第一阶段初始化完成之前,不能调用任何实话方法、不能读取任何实例属性的值,也不能引用self
- 知道第一阶段结束,实例才算完全合法
- 自动继承
- 如果子类没有自定义任何指定初始化器,它会自动继承父类所有的指定初始化器
- 如果子类提供了父类所有指定初始化器的实现(要么通过方式1继承,要么重写)
- 就算子类添加了更多的便捷初始化器,这些规则仍然适用
- 子类以便捷初始化器的形式重写父类的指定初始化器,也可以作为满足规则2的一部分