Swift学习42:初始化器

张建 lol

前言

  • 类、枚举、结构体 可以引入 初始化器。初始化器使用 关键字init来声明

  • 结构体、枚举、类 可以有任意数量的初始化器,但是 的初始化器不同 于结构体和枚举类有两种初始化器,即指定初始化器和便捷初始化器。

存储属性的初始赋值

  • 存储属性需要有默认值,而 结构体、枚举不需要

  • 类设置默认值方式也有两种:一种是 定义存储属性时设置默认值(Optional),另一种是通过 初始化器为存储属性设置默认值

  • 类的初始化器有两种,一种 指定初始化器,另一种 便捷初始化器

  • 指定初始化器又分为两种:一种 初始化器 不带参数,另一种 自定义初始化器 带参数

默认值

可选类型 的存储属性,不需要设置默认值,因为它本身 可能有值可能没有值,编译器会自动设置默认的初始化器

  • 直接设置默认值
1
2
3
4
5
6
class Person {
// 1、声明一个 Optional 默认值
var name: String?
// 2、直接设置默认值
var name: String = ""
}
  • 也可以通过 闭包 设置默认值
1
2
3
4
5
6
class Person {
var name: String {
// 在这个闭包中给 name 创建一个默认值
return "ZJ"
}
}

指定初始化器为存储属性设置默认值

初始化器创建实例时被调用,最简答的形式是不带任何参数的实例方法,已关键字 init 命名,即 指定初始化器

  • 可选类型的存储属性
1
2
3
clas Person {
var name: String?
}
  • 自定义初始化器设置默认值,带参数

可以通过 输入参数 来自定义初始化器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

class Person {
var name: String
// 0.不带参数
init() {
self.name = "ZJ"
}
// 1.实际参数和形式参数相同
init(name: String) {
self.name = name
}
// 2.实际参数 和 形式参数 不同
init(to name: String) {
self.name = name
}
// 3.通配符实际参数
init(_ name: String) {
self.name = name;
}
}
let p = Person(name: "ZJ")
let p1 = Person(to: "ZJ")
let p2 = Person("ZJ")

注:指定初始化器分为两种:一种是不带参数,一种是带参数
初始化器可以有任意数量

类的继承和构造

类中的所有存储属性->包括继承父类的所有存储属性:都必须在构造过程中 设置默认值

1、swift 中为类提供了两种初始化器:指定初始化器便捷初始化器

  • 指定初始化器

类中 主要的初始化器,设置类中所有属性默认值,并往上调用父类的初始化器设置所有属性的默认值

  • 便捷初始化器

类中 次要的、辅助型的初始化器,可以调用类中的指定初始化器,并提供默认值

2、指定初始化器和便捷初始化器语法

  • 指定初始化器和简单初始化器一样
1
2
3
init(parameters) {
statements
}
  • 便捷初始化器,需要在 init 前放置 convenience 关键字
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Person {
// 未设置默认值的存储属性
var name: String
// 指定初始化器 用来给存储属性设置默认值
init(name: String) {
self.name = name
}
// 便捷初始化器
convenience init() {
// 横向代理:必须调用一个指定的初始化器
self.init(name: "ZJ")
}
}
let p = Person()
print(p.name)

类的初始化器代理规则
1、指定初始化器必须调用其直接父类的指定初始化器
2、便捷初始化器必须调从同类调用一个指定初始化器
3、便捷初始化器最终必须调用一个指定初始化器

更方便的记忆方法
1、指定初始化器必须总是向上代理
2、便捷初始化器必须是横向代理

3、初始化器继承和重写

  • 子类默认是 不继承 父类的初始化器,实际上是通过 重写 父类的初始化器,切需要带上 override 关键字
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 继承和重写
class Person {
var name: String
init(name:String) {
self.name = name
}
}
class Student: Person {
// 重写父类的初始化器
override init(name: String) {
var newName = "my name is \(name)"
super .init(name: newName)
}
}
let s = Student(name: "ZJ")
print(s.name)

=======
my name is ZJ
  • 初始化器的自动继承

1、如果子类没有定义任何初始化器,它将自动继承父类的所有指定初始化器
2、如果子类实现了继承自父类的指定初始化器,那么它将自动继承父类的便捷初始化器

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Person {
var name: String
init(name:String) {
self.name = name
}
convenience init() {
self.init(name: "ZJ")
}
}
let p = Person()
print(p.name)
// 打印结果 ZJ

// 子类
class Student: Person {
var age: Int
// 本类的指定初始化器
init(name: String,age: Int) {
self.age = age
// 实现父类的指定初始化器
super.init(name: name)
}
convenience override init(name: String) {
self.init(name: name, age: 32)
}
}
let s = Student()
let s1 = Student(name: "ZJ")
let s2 = Student(name: "ZJ", age: 32)
print(s.age)
// 打印结果 32

安全检查

  • 子类指定初始化器向上委托父类初始化器前,子类的所有属性都要完成初始化
  • 之类指定初始化器必须先向上委托父类初始化器,才能修改父类的所有属性
  • 便捷初始化器必须先委托同类初始化器,才能为任意属性赋值
  • 方法的调用在所有指定初始化器之后。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// 安全检查
class Person {
var name: String
var age: Int
// 指定初始化器
init(name: String, age: Int) {
self.name = name
self.age = age
}
convenience init(){
self.init(name: "[Unnamed]", age: 0)
}
}
class Teacher: Person {
// 工资
var salary: Int
// 自己的指定初始化器
init(name: String, age: Int, salary: Int) {
// 1.先赋值自己的所有属性
self.salary = salary
// 2.调用父类的指定初始化器
super.init(name: name, age: age)
// 3.修改父类的所有属性
self.name = name + "老师"
// 6.调用方法
test()
}

func test() {
print("test")
}

convenience init(salary: Int) {
// 4.必须调用本类的指定初始化器
self.init(name: "ZJ", age: 32, salary: salary)
// 5.调用本类的指定初始化器后,才能赋值本类的所有属性
self.salary = self.salary + 1000
}
}

失败初始化器

如果在构造过程有可能失败,则需要定义一个可失败的初始化器,在 init 关键字 后面 添加 ?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Person {
var age: Int
init?(age: Int) {
if age > 200 {
return nil
}
age = age
}
}
let p = Person(age: 300)
print(p)

=====
nil

反初始化器

  • 类实例 被释放时,反初始化器立即被调用。用 deinit 关键字写反初始化器。

  • 反初始化器在 实例释放前自动被调用。不能自己调用。可以被子类继承。先子类 -> 父类

  • 每个类只能有一个

1
2
3
deinit {
// perform the deinitialization
}

必要初始化器

  • 在类的初始化器前加 required 修饰符表明所有该子类必须实现该初始化器
1
2
3
4
5
6
// 必要初始化器
class SomeClass {
required init(){
// 初始化器的实现代码
}
}
  • 子类重写父类的必要初始化器时,子类的初始化器前也添加 required 关键字,表明可继承
1
2
3
4
5
6
7
// 必要初始化器
class SomeSubClass: SomeClass {
required init(){
// 初始化器的实现代码
}
}

  • Post title:Swift学习42:初始化器
  • Post author:张建
  • Create time:2023-03-12 17:43:58
  • Post link:https://redefine.ohevan.com/2023/03/12/Swift课程/Swift学习42:初始化器/
  • Copyright Notice:All articles in this blog are licensed under BY-NC-SA unless stating additionally.