在这个Swift教程中,我们将讨论一个重要的概念,即Swift init或Swift初始化。
快速启动( )
初始化是为使用准备一类、结构或列表的实例的过程,该过程涉及在该实例中为每个存储的属性设置一个初始值,并在新实例准备使用之前执行任何其他设置或初始化。
初始化器类似于 Java 编程中的构建器。Swift 是一种类型安全的语言,为初始化器设定了很多规则。
快速 init() 语法
1init() {
2 // initialise the stored properties here.
3}
让我们看看下面的样本类。
1class A{
2
3 //Compilation error. No initializer is defined.
4 var a : Int
5 var b : String
6 var c : Int?
7 let website = "JournalDev"
8}
上面的类别不会编译. 快速编译器抱怨存储的属性没有初始化. 存储的属性不能保存在未定状态。
- 在属性定义本身中分配一个默认属性值
- 使用初始化器,
init()
来初始化属性
让我们看看每一个方法一次。
1class A{
2
3 var a : Int = 5
4 var b : String = "Hello. How you're doing"
5 var c : Int?
6 let website = "JournalDev"
7}
在这里,我们为每个存储的属性设置了默认值,因此Swift将默认的初始化器给我们。
1var object = A()
2object.a = 10
3object.c = 2
第二种方法是使用如下所示的init()
方法来初始化存储的属性。
1class A{
2
3 var a : Int
4 var b : String
5 var c : Int?
6 let website = "JournalDev"
7
8 init(a: Int, b: String) {
9 self.a = a
10 self.b = b
11 }
12}
13
14var object = A(a: 5, b: "Hello World")
** 注意**: Swift Optional不是存储属性,因此不需要初始化。存储属性是使用自我
属性在init()
方法中访问的。 ** 注意**:自我
被用来指向其自身实例方法中的当前实例(类似于java
中的this
).上面的初始化器是类的主要初始化器。
1class A{
2
3 var a : Int
4 var b : String
5 var c : Int?
6 let website : String
7
8 init(a: Int, b: String, website: String) {
9 self.a = a
10 self.b = b
11 self.website = website
12 }
13}
14
15var object = A(a: 5,b: "Hello World", website: "JournalDev")
结构的初始化器
结构作为值类型,不必定义初始化器。 结构类型会自动接收一个会员式初始化器,除非您已定义了自定义初始化器(s)。
1struct Rect{
2 var length : Int
3 var breadth : Int
4}
5var r = Rect(length: 5, breadth: 10)
1struct Rect{
2 var length : Int = 5
3 var breadth : Int = 10
4}
5
6var r = Rect()
7var r1 = Rect(length: 10, breadth: 5)
由于我们已将默认值分配到上面的片段中存储的属性中,我们将收到一个默认初始化器,而没有会员初始化,以及会员初始化器。
1struct Rect{
2 var length : Int
3 var breadth : Int
4
5 init(length: Int, breadth: Int) {
6 self.length = length + 10
7 self.breadth = breadth + 10
8 }
9}
10var r = Rect(length: 10, breadth: 5)
在上述情况下,我们已经定义了我们自己的自定义初始化器。 ** 使用无外部名称的参数** 当初始化器不需要外部名称时,使用_
来表示如下所示。
1class A{
2
3 var a : Int
4 var b : String
5 var c : Int?
6 let website = "JournalDev"
7
8 init(_ a: Int, _ b: String) {
9 self.a = a
10 self.b = b
11 }
12}
13
14var object = A(5,"Hello World")
1struct Rect{
2 var length : Int
3 var breadth : Int
4
5 init(_ length: Int, _ breadth: Int) {
6 self.length = length + 10
7 self.breadth = breadth + 10
8 }
9}
10var r = Rect(10, 10)
Swift初始化器的类型
类的初始化器可以广泛分为以下类型:
- 指定初始化器: 这是该类的主要初始化器。 它必须在调用任何超级类初始化器之前完全初始化其类所引入的所有属性。 一个类可以有多个指定初始化器。 每个类必须至少有一个指定初始化器
- 便利性初始化器: 这些是辅助的,支持一个类的初始化器。 它们必须调用同一类的指定初始化器。 这些是可选的,可用于自定义设置。 它们以相同的风格写成,但在
方便
修改器之前放置到init
关键字
1class Student{
2
3 var name : String
4 var degree : String
5
6 init(name : String, degree: String) {
7 self.name = name
8 self.degree = degree
9 }
10
11 convenience init()
12 {
13 self.init(name: "Unnamed", degree: "Computer Science")
14 }
15
16}
17var student = Student()
18student.degree // "Computer Science"
19student.name // "Unnamed"
实用性初始化器在将默认值分配到存储的属性时非常有用。
Swift Initializer 代表值类型
可以将一个初始化器从另一个呼叫,从而避免代码重复。 像结构这样的值类型不支持继承。 因此,唯一可能的方法是在同一个结构内呼叫初始化器。
1struct Rect{
2 var length : Int
3 var breadth : Int
4
5 init(_ length: Int, _ breadth: Int) {
6 self.length = length
7 self.breadth = breadth
8 }
9
10 init(_ length: Int)
11 {
12 self.init(length, length)
13 }
14}
15var r = Rect(10, 5)
16var r1 = Rect(15) //initialises the length and breadth to 15
Swift Initializer 参照类型代表
类作为参考类型支持继承,因此初始化者可以从超级类呼叫其他初始化者,从而增加责任,以正确地继承和初始化所有值。
- 指定的初始化器必须从其直接的超级类号召指定的初始化器。 _) * 方便初始化器必须从同一类号召另一个初始化器。
下图描述了上述规则。
**指定的初始化器必须始终委托,方便初始化器必须始终委托。
Swift Initializer 继承与转移
在Swift中,子类在默认情况下不会继承他们的超级级别的初始化器,除非满足某些条件(自动初始化器继承)。 这样做是为了防止子类中半批初始化。 让我们看看指定的和便利性初始化器如何通过继承运作。 我们将定义一个车辆基础类,将由相关子类继承。 我们将使用(Enums)(/community/tutorials/swift-enum)作为类型。
1enum VehicleType : String {
2 case twoWheeler = "TwoWheeler"
3 case fourWheeler = "FourWheeler"
4}
5
6class Vehicle{
7
8 var vehicleType : VehicleType
9
10 init(vehicleType: VehicleType) {
11 self.vehicleType = vehicleType
12 print("Class Vehicle. vehicleType is \(self.vehicleType.rawValue)\n")
13 }
14
15 convenience init()
16 {
17 self.init(vehicleType: .fourWheeler)
18 }
19}
20
21var v = Vehicle(vehicleType: .twoWheeler)
** 注意**:便利性初始化器必须使用self.init
来调用相同类的指定初始化器 让我们定义上面的类的子类,如下所示。
1enum TwoWheelerType : String
2{
3 case scooty = "Scooty"
4 case bike = "Bike"
5}
6
7class TwoWheeler : Vehicle{
8
9 var twoWheelerType : TwoWheelerType
10 var manufacturer : String
11
12 init(twoWheelerType : TwoWheelerType, manufacturer : String, vType : VehicleType) {
13 self.twoWheelerType = twoWheelerType
14 self.manufacturer = manufacturer
15 print("Class TwoWheeler. \(self.twoWheelerType.rawValue) manufacturer is \(self.manufacturer)")
16 super.init(vehicleType: vType)
17
18 }
19}
重要点要注意:
- 子类的指定初始化器必须在调用超级类的指定初始化器之前初始化其自身属性
- 子类只能在调用
super.init
后修改超级类的继承属性
以下代码会导致编译时间错误。
1class TwoWheeler : Vehicle{
2
3 var twoWheelerType : TwoWheelerType
4 var manufacturer : String
5
6 init(twoWheelerType : TwoWheelerType, manufacturer : String, vType : VehicleType) {
7 self.twoWheelerType = twoWheelerType
8 self.manufacturer = manufacturer
9 self.vehicleType = vType //Won't compile
10 super.init(vehicleType: vType)
11 //self.vehicleType = .fourWheeler //This would work.
12
13 }
14}
15
16var t = TwoWheeler(twoWheelerType: .scooty, manufacturer: "Hero Honda", vType: .twoWheeler)
如前所述,超级类初始化器不会自动在子类中继承,因此下面的初始化将失败。
1var t = TwoWheeler(vehicleType: .twoWheeler) //manufacturer property isn't initialized.
要翻译初始化器,子类初始化器必须与超级类的指定初始化器相匹配.在这种情况下,附加到初始化器的‘翻译’关键字。
1class TwoWheeler : Vehicle{
2
3 var twoWheelerType : TwoWheelerType
4 var manufacturer : String
5
6 init(twoWheelerType : TwoWheelerType, manufacturer : String, vType : VehicleType) {
7 self.twoWheelerType = twoWheelerType
8 self.manufacturer = manufacturer
9 print("Class TwoWheeler. \(self.twoWheelerType.rawValue) manufacturer is \(self.manufacturer)")
10 super.init(vehicleType: vType)
11
12 }
13
14 override init(vehicleType: VehicleType)
15 {
16 print("Class TwoWheeler. Overriden Initializer. \(vehicleType.rawValue)")
17 self.twoWheelerType = .bike
18 self.manufacturer = "Not defined"
19 super.init(vehicleType: vehicleType)
20 }
下面的初始化器不超过来自超级类的初始化器,因为参数名称不同。
1//This would give a compile-time error since the parameter v doesn't match with the superclass.
2override init(v: VehicleType)
3 {
4 self.twoWheelerType = .bike
5 self.manufacturer = "Not defined"
6 super.init(vehicleType: v)
7 }
使用便利性初始化器来取代来自超级阶级的初始化。
1class TwoWheeler : Vehicle{
2
3 var twoWheelerType : TwoWheelerType
4 var manufacturer : String
5
6 init(twoWheelerType : TwoWheelerType, manufacturer : String, vType : VehicleType) {
7 self.twoWheelerType = twoWheelerType
8 self.manufacturer = manufacturer
9 print("Class TwoWheeler. \(self.twoWheelerType.rawValue) manufacturer is \(self.manufacturer)")
10 super.init(vehicleType: vType)
11
12 }
13
14 override convenience init(vehicleType: VehicleType) {
15 self.init(twoWheelerType: .bike, manufacturer: "Not Defined", vType: .twoWheeler)
16 self.vehicleType = vehicleType
17 }
18}
19var t = TwoWheeler(twoWheelerType: .scooty, manufacturer: "Hero Honda", vType: .twoWheeler)
20t = TwoWheeler(vehicleType: .twoWheeler)
21
22//Output
23Following gets printed on the console:
24Class TwoWheeler. Scooty manufacturer is Hero Honda
25Class Vehicle. vehicleType is TwoWheeler
26
27Class TwoWheeler. Bike manufacturer is Not Defined
28Class Vehicle. vehicleType is TwoWheeler
实用性初始化器附带的关键字是override
。它呼叫相同类别的指定的 initalizer。 ** 注意**:关键字 convenience
和override
的顺序并不重要。
需要的初始化
在初始化器之前写入关键字必需
表示每个子类必须执行该初始化器。
1class Vehicle{
2
3 var vehicleType : VehicleType
4
5 required init(vehicleType: VehicleType) {
6 self.vehicleType = vehicleType
7 print("Class Vehicle. vehicleType is \(self.vehicleType.rawValue)\n")
8 }
9
10 convenience init()
11 {
12 self.init(vehicleType: .fourWheeler)
13 }
14}
15
16class TwoWheeler : Vehicle{
17
18 var twoWheelerType : TwoWheelerType
19 var manufacturer : String
20
21 init(twoWheelerType : TwoWheelerType, manufacturer : String, vType : VehicleType) {
22 self.twoWheelerType = twoWheelerType
23 self.manufacturer = manufacturer
24 print("Class TwoWheeler. \(self.twoWheelerType.rawValue) manufacturer is \(self.manufacturer)")
25 super.init(vehicleType: vType)
26
27 }
28
29 required init(vehicleType: VehicleType) {
30 self.manufacturer = "Not Defined"
31 self.twoWheelerType = .bike
32 super.init(vehicleType: vehicleType)
33 }
34}
** 注意**:添加必要的修改器表示初始化器将被翻译。因此,在上述情况下,可以省略翻译关键字。 ** 使用必要的初始化器与便利性** 必要的初始化器和便利性初始化器是相互独立的,可以一起使用。
1enum FourWheelerType : String
2{
3 case car = "Car"
4 case bus = "Bus"
5 case truck = "Truck"
6}
7
8class FourWheeler : Vehicle
9{
10 var fourWheelerType : FourWheelerType
11 var name : String
12
13 init(fourWheelerType : FourWheelerType, name: String, vehicleType: VehicleType) {
14 self.fourWheelerType = fourWheelerType
15 self.name = name
16 print("Class FourWheeler. \(self.fourWheelerType.rawValue) Model is \(self.name)")
17 super.init(vehicleType: vehicleType)
18 self.vehicleType = vehicleType
19 }
20
21 required convenience init(vehicleType: VehicleType) {
22 self.init(fourWheelerType: .bus, name: "Mercedes", vehicleType: vehicleType)
23 }
24}
25
26class Car : FourWheeler{
27
28 var model : String
29
30 init(model: String) {
31 self.model = model
32 print("Class Car. Model is \(self.model)")
33 super.init(fourWheelerType: .car, name: self.model, vehicleType: .fourWheeler)
34 }
35
36 required init(vehicleType: VehicleType)
37 {
38 self.model = "Not defined"
39 print("Class Car. Model is \(self.model)")
40 super.init(fourWheelerType: .car, name: self.model, vehicleType: vehicleType)
41 }
42
43}
重要事项要注意在上面的代码片段:
- 实用性初始化器是类中的次要初始化器
- 将实用性初始化器设置为要求意味着在子类中实现它是强制性的
自动初始化继承
有两种情况下,子类会自动继承从超级类的初始化器。
- 不要在子类中定义任何指定的初始化器
- 执行超级类的所有指定的初始化器。
行动中的第一个规则在下面的片段中展示了:
1class Name {
2
3 var name: String
4
5 init(n: String) {
6 self.name = n
7 }
8}
9
10class Tutorial: Name {
11
12 var tutorial : String? = "Swift Initialization"
13}
14
15var parentObject = Name(n: "Anupam")
16var childObject = Tutorial(n: "JournalDev")
行动中的第二个规则在下面的片段中展示。
1class Name {
2
3 var name: String
4
5 init(n: String) {
6 self.name = n
7 }
8
9 convenience init()
10 {
11 self.init(n: "No name assigned")
12 }
13}
14
15class Tutorial: Name {
16
17 var tutorial : String? = "Swift Tutorial"
18
19 override init(n : String) {
20 super.init(n: n)
21 }
22}
23
24var parentObject = Name(n: "Anupam")
25var childObject = Tutorial(n: "JournalDev")
26var childObject2 = Tutorial()
27print(childObject2.name) //prints "No name assigned
超级类的便利性初始化器在上面的代码中自动在子类中可用。
快速失败初始化器
在类、结构或编号中,我们可以使用关键字init?
来定义一个可能失败的初始化程序,该关键字在初始化过程失败时会被触发。初始化可以由于各种原因失败:无效的参数值、缺少外部源等。
1struct SName {
2 let name: String
3 init?(name: String) {
4 if name.isEmpty { return nil }
5 self.name = name
6 }
7}
8
9var name = SName(name: "JournalDev")
10if name != nil {
11 print("init success") //this gets displayed
12}
13else{
14 print("init failed")
15}
16name = SName(name: "")
17
18if name != nil {
19 print("init success")
20}
21else{
22 print("init failed") //this gets displayed
23}
可用初始化器与Enums
1enum CharacterExists {
2 case A, B
3 init?(symbol: Character) {
4 switch symbol {
5 case "A":
6 self = .A
7 case "B":
8 self = .B
9 default:
10 return nil
11 }
12 }
13}
14
15let ch = CharacterExists(symbol: "C")
16if ch != nil {
17 print("Init failed. Character doesn't exist")
18}
1class CName {
2 let name: String
3 init?(name: String) {
4 if name.isEmpty { return nil }
5 self.name = name
6 }
7}
8var name = CName(name: "")
9
10if name != nil {
11 print("init success")
12}
13else{
14 print("init failed")
15}
注:错误的初始化器和非错误的初始化器不能具有相同的参数类型和名称。
错误的初始化器
在您的子类中,您可以替代失败的初始化器。失败的初始化器可以替代非失败的初始化器,但不能替代。
1class CName {
2 let name: String
3 init?(name: String) {
4 if name.isEmpty { return nil }
5 self.name = name
6 }
7}
8var name = CName(name: "")
9
10class SubName : CName{
11
12 var age : Int
13 override init(name: String)
14 {
15 self.age = 23
16 super.init(name: name)!
17 }
18}
** 注意**:强制解包用于调用来自超级类的失败初始化器,作为子类的非失败初始化器的实现的一部分。