存储值属性赋值
类和结构体在创建实例时,必须为所有存储型属性设置合适的初始值。
存储型属性的值不能处于一个未知的状态。
可选属性,默认值是nil
有两种方式设置初始值:
1、构造器:构造器中为存储型属性设置初始值
2、默认属性值:定义属性时分配默认值
默认构造器
类或结构体,在没有提供自定义的初始化方法时,都会有一个默认的构造器:
1、结构体如果没有定义任何自定义构造器,它们将自动获得一个逐一成员构造器
2、类默认有一个不带任何参数的构造器:比如这样 classA() 就可以构造一个实例
枚举若是没有定义类型,就没有默认构造器
枚举若是定义了类型,就有一个可失败的原始值构造器
值类型的构造代理
值类型(结构体和枚举类型)不支持继承,所以构造器代理的过程相对简单,因为它们只能代理给自己的其它构造器
(就是只能横向代理)
如果你为某个值类型定义了一个自定义的构造器,你将无法访问到默认构造器(如果是结构体,还将无法访问逐一成员构造器)
值类型的构造器(结构体)。假如你希望默认构造器、逐一成员构造器以及你自己的自定义构造器都能用来创建实例,可以将自定义的构造器写到扩展(extension)中,而不是写在值类型的原始定义中。
类的继承和构造过程
一个对象的内存只有在其所有存储型属性确定之后才能完全初始化
Swift中,类的构造器分两个过程:一是类中的每个存储型属性赋一个初始值;二是构造方法里
Swift 为类类型提供了两种构造器来确保实例中所有存储型属性都能获得初始值,它们被称为指定构造器和便利构造器
1、指定构造器和便利构造器
指定构造器是类中最主要的构造器。必须总是向上代理
便利构造器是类中比较次要的、辅助型的构造器。必须总是横向代理
为了简化指定构造器和便利构造器之间的调用关系,Swift 构造器之间的代理调用遵循以下三条规则:
规则 1
指定构造器必须调用其直接父类的的指定构造器。
规则 2
便利构造器必须调用同类中定义的其它构造器。
规则 3
便利构造器最后必须调用指定构造器。
指定构造器和便利构造器的关系图.png
2、构造器的继承和重写
跟 Objective-C 中的子类不同,Swift 中的子类默认情况下不会继承父类的构造器。
父类的构造器仅会在安全和适当的某些情况下被继承
要重写父类的构造器(指定构造器、便利构造器),都要在构造器前面加 override 修饰符
不是很重要的一个点:
如果子类的构造器没有在阶段 2 过程中做自定义操作,并且父类有一个无参数的指定构造器,你可以在所有子类的存储属性赋值之后省略 super.init() 的调用。
3、构造器的自动继承
假设你为子类中引入的所有新属性都提供了默认值,以下 2 个规则将适用:
规则 1
如果子类没有定义任何指定构造器,它将自动继承父类所有的指定构造器。
规则 2
如果子类提供了所有父类指定构造器的实现——无论是通过规则 1 继承过来的,还是提供了自定义实现——它将自动继承父类所有的便利构造器。
即使你在子类中添加了更多的便利构造器,这两条规则仍然适用。
注意
子类可以将父类的指定构造器实现为便利构造器来满足规则 2。
4、很经典的一个实践用例
class Food {
var name: String
init(name: String) {
self.name = name
}
convenience init() {
self.init(name: "[Unnamed]")
}
}
class RecipeIngredient: Food {
var quantity: Int
init(name: String, quantity: Int) {
self.quantity = quantity
super.init(name: name)
}
override convenience init(name: String) {
self.init(name: name, quantity: 1)
}
}
class ShoppingListItem: RecipeIngredient {
var purchased = false
var description: String {
var output = "\(quantity) x \(name)"
output += purchased ? " ✔" : " ✘"
return output
}
}
image.png
可失败的构造器
其语法为在 init 关键字后面添加问号(init?)
严格来说,构造器都不支持返回值。因为构造器本身的作用,只是为了确保对象能被正确构造。因此你只是用 return nil 表明可失败构造器构造失败,而不要用关键字 return 来表明构造成功。
带原始值的枚举类型会自带一个可失败构造器 init?(rawValue:)
类、结构体、枚举的可失败构造器可以横向代理到它们自己其他的可失败构造器。类似的,子类的可失败构造器也能向上代理到父类的可失败构造器
参考链接:https://docs.swift.org/swift-book/LanguageGuide/Initialization.html
网友评论