构造方法是为了使用某个类、结构体和枚举类型的实例而进行的准备过程。这个过程包含了为实例中的每个属性设置初始值和为其执行必要的准备和初始化任务。Swift构造方法使用init()方法
1 | init(参数列表){ 初始化代码 } |
与OC中的构造器不同,Swift的构造器无需返回值,他们主要的任务是保证新实例在第一次使用前完成正确的初始化。类实例也可以通过定义析构器(deinitializer)在类实例释放之前执行清理内存的工作
注意点:
- 在Swift中类/结构体/枚举都需要构造方法
- 构造方法的作用仅仅是用于初始化属性,而不是分配内存,分配内存是系统帮我们做的
- 构造方法是隐式调用的,通过
类名称()
形式创建一个对象就会隐式调用init()构造方法 - 如果所有的存储属性都有默认值,可以不提供构造方法,系统会提供一个隐式的构造方法
- 如果存储属性可以提供缺省,那么提倡大家使用设置缺省值得方式,这样可以简化代码(不用自定义构造法,不用写存储属性类型)
存储属性的初始赋值
- 类和结构体在实例创建是,必须为所有存储属性设置合适的初始值。
- 存储属性在构造器中赋值是,它们的值是被直接设置的,不会触发任何属性观测器
存储属性在构造器中的赋值流程:
- 创建初始值
- 在属性定义中指定默认属性值
- 初始化实例,并调用init()方法
不带参数构造方法
1 | class Person { |
带参数构造方法
1 | class Person1 { |
常量属性&构造方法
常量存储属性只能通过缺省值或在构造方法中被修改,其他任何地方都不能修改
1 | class Person2 { |
可选属性&构造方法
如果属性是可选类型,那么可选值存储属性可以不在构造方法中初始化,也就是说可选值在对象构造完毕后不用初始化,其实如果不对可选存储属性进行初始化,默认就是nil
1 | class Car { |
结构体构造方法
1 | struct Rect { |
注意:
- 在类中默认是没有逐一构造器的
- 如果在结构体中自定义了构造方法,那么系统不会生成默认的逐一构造器
- 如果给存储属性提供缺省值,系统还是会提供默认的逐一构造器
- 如果给存储属性提供缺省值,可以使用不带参数的方法初始化结构体
构造器代理
构造器代理:构造方法可以调用其他构造方法来完成实例的构造,称之为构造器代理(构造方法之间互相调用)
好处:减少构造方法之间的重复代码
1 | struct Rect1 { |
构造器代理规则
值类型 | 类类型 |
---|---|
不支持继承,所以构造器代理的过程相对简单,因为他们只能代理本身提供的其他构造器。你可以使用self.init在自定义的构造器中引用其他的属于相同值类型的构造器 | 他可以继承自其他类,这意味着类有责任保证其所有继承的存储属性在构造时也能正确初始化 |
继承与构造方法
指定构造方法&便利构造方法
1 | class Person4 { |
派生类的构造方法
1 | class Person5 { |
构造器间的调用规则
- 子类指定构造器必须调用其直接父类的“指定构造器”
- 便利构造器必须调用同类中的其他构造器(指定或便利)
- 便利构造器必须最终以调用一个指定构造器结束(无论调用是指定还是便利,最终肯定会调用一个指定构造器)
Tip:
- 指定构造器总是向上代理(父类)
- 便利构造器总是横向代理(当前类)
1 | class Person5 { |
两段式构造
构造过程可以分为两个阶段:
- 确保当前类和父类所有存储属性都被初始化
- 做一些其他初始化操作
好处:
- 可以防止属性在被初始化之前访问
- 可以防止属性被另外一个构造器意外赋值
注意:构造器的初始化永远是在所有类的第一阶段初始化之后开始第二阶段
编译器安全检查:
- 必须先初始化子类特有属性,再向上代理父类指定构造方法初始化父类属性
- 只能在调用完父类指定构造器后才能访问父类属性
- 在便利构造器中,必须先调用同类其他构造方法后才能访问属性
- 第一阶段完成前不能访问父类属性,也不能引用self和调用任何实例方法
1 | class Person5 { |
重写构造方法
1 | class Person5 { |
构造方法的自动继承
- 如果子类中没有定义任何构造器,且子类中所有的存储属性都有缺省值,会继承父类中所有的构造方法(包括便利构造器)
- 如果子类只是重写了父类中的某些指定构造器,不管子类中的存储舒心是否有缺省值,都不会继承父类中的其他构造器
- 如果子类重写了父类中所有的指定构造器,不管子类中的存储属性是否有缺省值,都会同事继承父类中的所有便利构造方法
1 | class Person6 { |
required构造方法
只要在构造方法前面加上一个required关键字,那么所有的子类(后续子类)只要定义了构造方法都必须实现该构造方法
1 | class Person7 { |
参考: