初始化器
This commit is contained in:
@@ -223,3 +223,8 @@ circle.radius = 10
|
||||
被 `final` 修饰的方法、下标、属性,禁止被重写
|
||||
|
||||
被 `final` 修饰的类,禁止被继承
|
||||
|
||||
#### 多态
|
||||
|
||||
父类引用指向子类对象
|
||||
|
||||
|
Binary file not shown.
104
14 初始化.playground/Contents.swift
Normal file
104
14 初始化.playground/Contents.swift
Normal file
@@ -0,0 +1,104 @@
|
||||
import UIKit
|
||||
|
||||
// 类的属性有初始值的时候,默认会有一个 init() 的初始化器
|
||||
//class Size {
|
||||
// var width: Int = 0
|
||||
// var height: Int = 0
|
||||
//}
|
||||
|
||||
// 等价于
|
||||
//class Size {
|
||||
// var width: Int
|
||||
// var height: Int
|
||||
//
|
||||
// init() {
|
||||
// width = 0
|
||||
// height = 0
|
||||
// }
|
||||
//}
|
||||
|
||||
|
||||
class Size {
|
||||
var width: Int = 0
|
||||
var height: Int = 0
|
||||
|
||||
// 指定初始化器(主要初始化器)
|
||||
// 用户指定完初始化器之后,会覆盖掉原来的 init()初始化器
|
||||
init(width: Int, height: Int) {
|
||||
self.width = width
|
||||
self.height = height
|
||||
}
|
||||
|
||||
// 便捷初始化器
|
||||
convenience init(width: Int) {
|
||||
self.init(width: width, height: 0)
|
||||
}
|
||||
}
|
||||
|
||||
var s1 = Size(width: 10, height: 20)
|
||||
var s2 = Size(width: 30)
|
||||
|
||||
|
||||
class Person {
|
||||
var age: Int
|
||||
// 指定初始化器
|
||||
init(age: Int) {
|
||||
self.age = age
|
||||
}
|
||||
// 便捷初始化器
|
||||
convenience init() {
|
||||
self.init(age: 0)
|
||||
}
|
||||
}
|
||||
|
||||
class Student: Person {
|
||||
var score: Int
|
||||
// 指定初始化器调用直系父类的初始化器
|
||||
init(age: Int, score: Int) {
|
||||
self.score = score
|
||||
// super.init 方法放到最后
|
||||
super.init(age: age)
|
||||
}
|
||||
|
||||
// 便捷初始化器调用便捷初始化器
|
||||
convenience init() {
|
||||
self.init(score: 0)
|
||||
}
|
||||
|
||||
// 便捷初始化器调用指定初始化器
|
||||
convenience init(score: Int) {
|
||||
self.init(age: 0, score: score)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class Animal {
|
||||
var legs: Int
|
||||
var name: String
|
||||
var age: Int
|
||||
|
||||
init(name: String, age: Int, legs: Int) {
|
||||
self.legs = legs
|
||||
self.age = age
|
||||
self.name = name
|
||||
}
|
||||
|
||||
init(name: String, age: Int) {
|
||||
self.legs = 4
|
||||
self.age = age
|
||||
self.name = name
|
||||
}
|
||||
|
||||
convenience init(name: String) {
|
||||
self.init(name: name, age: 1, legs: 4)
|
||||
}
|
||||
}
|
||||
|
||||
class Cat: Animal {
|
||||
|
||||
}
|
||||
|
||||
var cat = Cat(name: "淘气", age: 3, legs: 4)
|
||||
var cat1 = Cat(name: "淘气", age: 3)
|
||||
var cat2 = Cat(name: "淘气")
|
||||
|
175
14 初始化.playground/Resources/README.md
Normal file
175
14 初始化.playground/Resources/README.md
Normal file
@@ -0,0 +1,175 @@
|
||||
---
|
||||
gitea: none
|
||||
include_toc: true
|
||||
---
|
||||
|
||||
### 初始化器
|
||||
|
||||
类、结构体、枚举都可以定义初始化器。类的两种初始化器如下所示
|
||||
|
||||
* 指定初始化器(designated initializer)
|
||||
* 便捷初始化器(convenience initializer): 便捷初始化器的前边有 `convenience` 关键字,只能进行当前类横向调用。
|
||||
|
||||
```swift
|
||||
// 类的属性有初始值的时候,默认会有一个 init() 的初始化器
|
||||
class Size {
|
||||
var width: Int = 0
|
||||
var height: Int = 0
|
||||
}
|
||||
|
||||
// 等价于
|
||||
class Size {
|
||||
var width: Int
|
||||
var height: Int
|
||||
// 指定初始化器
|
||||
init() {
|
||||
width = 0
|
||||
height = 0
|
||||
}
|
||||
}
|
||||
|
||||
class Size {
|
||||
var width: Int = 0
|
||||
var height: Int = 0
|
||||
|
||||
// 指定初始化器(主要初始化器)
|
||||
// 用户指定完初始化器之后,会覆盖掉原来的 init()初始化器
|
||||
init(width: Int, height: Int) {
|
||||
self.width = width
|
||||
self.height = height
|
||||
}
|
||||
|
||||
// 便捷初始化器
|
||||
convenience init(width: Int) {
|
||||
self.init(width: width, height: 0)
|
||||
}
|
||||
}
|
||||
var s1 = Size(width: 10, height: 20)
|
||||
var s2 = Size(width: 30)
|
||||
```
|
||||
|
||||
#### 类初始化器
|
||||
|
||||
1. 每个类至少有一个指定初始化器,指定初始化器是类的主要初始化器
|
||||
2. 默认初始化器总是类的指定初始化器
|
||||
3. 类偏向于少量指定初始化器,一个类通常只有一个指定初始化器
|
||||
|
||||
|
||||
|
||||
#### 初始化器的相互调用
|
||||
|
||||
1. 指定初始化器必须从它的直系父类调用指定初始化器
|
||||
2. 便捷初始化器必须从相同的类里调用另一个初始化器
|
||||
3. 便捷初始化器最终必须调用一个指定初始化器
|
||||
|
||||
```swift
|
||||
class Person {
|
||||
var age: Int
|
||||
// 指定初始化器
|
||||
init(age: Int) {
|
||||
self.age = age
|
||||
}
|
||||
// 便捷初始化器
|
||||
convenience init() {
|
||||
self.init(age: 0)
|
||||
}
|
||||
}
|
||||
|
||||
class Student: Person {
|
||||
var score: Int
|
||||
// 指定初始化器调用直系父类的初始化器
|
||||
init(age: Int, score: Int) {
|
||||
self.score = score
|
||||
// super.init 方法放到最后
|
||||
super.init(age: age)
|
||||
// 个性化定制代码
|
||||
...
|
||||
}
|
||||
|
||||
// 便捷初始化器调用便捷初始化器
|
||||
convenience init() {
|
||||
self.init(score: 0)
|
||||
}
|
||||
|
||||
// 便捷初始化器调用指定初始化器
|
||||
convenience init(score: Int) {
|
||||
self.init(age: 0, score: score)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
初始化器的调用规则如下图所示
|
||||
|
||||
<img src="/Users/jiulinxiri/Library/Application%20Support/typora-user-images/image-20220113091257659.png" alt="image-20220113091257659" style="zoom:50%;" />
|
||||
|
||||
|
||||
|
||||
#### 两段式初始化
|
||||
|
||||
第1阶段:初始化所有存储属性
|
||||
|
||||
* 外层调用指定\便捷初始化器
|
||||
* 分配内存给实例,但未初始化
|
||||
* 指定初始化器确保当前类定义的存储属性都初始化
|
||||
* 指定初始化器调用父类的初始化器,不断向上调用,形成初始化器链
|
||||
|
||||
第2阶段:设置新的存储属性值
|
||||
|
||||
* 从顶部初始化器往下,链中的每一个指定初始化器都有机会进一步定制实例
|
||||
* 初始化器现在能够使用self(访问、修改它的属性,调用它的实例方法等等)
|
||||
* 最终,链中任何便捷初始化器都有机会定制实例以及使用self
|
||||
|
||||
|
||||
|
||||
#### 重写
|
||||
|
||||
初始化器的重写,即子类重写父类的初始化器方法。
|
||||
|
||||
* 当重写父类的指定初始化器时,必须加上 `override`(即使子类的实现是便捷初始化器)
|
||||
* 如果子类写了一个匹配父类便捷初始化器的初始化器,不用加上 `override`
|
||||
* 因为父类的便捷初始化器永远不会通过子类直接调用
|
||||
|
||||
#### 自动继承
|
||||
|
||||
①如果子类没有自定义任何指定初始化器,它会自动继承父类所有的指定初始化器。
|
||||
|
||||
```swift
|
||||
class Animal {
|
||||
var legs: Int
|
||||
var name: String
|
||||
var age: Int
|
||||
|
||||
init(name: String, age: Int, legs: Int) {
|
||||
self.legs = legs
|
||||
self.age = age
|
||||
self.name = name
|
||||
}
|
||||
|
||||
init(name: String, age: Int) {
|
||||
self.legs = 4
|
||||
self.age = age
|
||||
self.name = name
|
||||
}
|
||||
|
||||
convenience init(name: String) {
|
||||
self.init(name: name, age: 1, legs: 4)
|
||||
}
|
||||
}
|
||||
|
||||
class Cat: Animal {
|
||||
|
||||
}
|
||||
// Cat 继承父类所有的指定初始化器
|
||||
var cat = Cat(name: "淘气", age: 3, legs: 4)
|
||||
var cat1 = Cat(name: "淘气", age: 3)
|
||||
// 子类自动继承所有的父类便捷初始化器
|
||||
var cat2 = Cat(name: "淘气")
|
||||
```
|
||||
|
||||
②如果子类提供了父类所有指定初始化器的实现(要么通过方式①继承,要么重写)
|
||||
|
||||
* 子类自动继承所有的父类便捷初始化器
|
||||
|
||||
③就算子类添加了更多的便捷初始化器,这些规则仍然适用
|
||||
|
||||
④子类以便捷初始化器的形式重写父类的指定初始化器,也可以作为满足规则②的一部分
|
4
14 初始化.playground/contents.xcplayground
Normal file
4
14 初始化.playground/contents.xcplayground
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<playground version='5.0' target-platform='ios' buildActiveScheme='true' importAppTypes='true'>
|
||||
<timeline fileName='timeline.xctimeline'/>
|
||||
</playground>
|
7
14 初始化.playground/playground.xcworkspace/contents.xcworkspacedata
generated
Normal file
7
14 初始化.playground/playground.xcworkspace/contents.xcworkspacedata
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "group:">
|
||||
</FileRef>
|
||||
</Workspace>
|
Binary file not shown.
Reference in New Issue
Block a user