Swift 为类提供了两种构造器,分别是指定构造器和便利构造器。
- 指定构造器必须总是向上代理(重写、重载)
- 便利构造器必须总是横向代理
![](https://img.haomeiwen.com/i2974330/9164800123697991.png)
重写构造函数
override
-
非 Optional 属性,都必须在构造函数中设置初始值,从而保证对象在被实例化的时候,属性都被正确初始化。
-
顺序:分段进行,先初始化子类(保证必选属性有值),再初始化父类(super.init())。
- super.init() 是对象构造结束的标记,可以省略但是不建议,保持代码执行线索的可读性。
- 若使用属性,需要在子类初始化完成的时候
- 若使用方法,要在初始化工作完成之后
-
Swift 中的构造函数不用写 func
class Person: NSObject {
var name: String // 必选属性需要在初始化器中赋初值
/**
重写 override
父类已经存在的方法或者属性,子类需要重写做特殊操作的时候 可以重写。
特点:在方法的内部可以 super
*/
override init() {
// name = "zhangsan"
// Property 'self.name' not initialized at super.init call
super.init()
}
}
-
UIViewController 是没有构造函数 init()的,所以可以直接写 init(),之后补上必须构造函数即可
UIViewController 构造函数的重载
重载构造函数
overload:函数名相同,函数的参数类型或者参数的个数不同,函数就形成了重载,任何函数都可以形成重载
如果本类构造函数发生了重载,本类中所有没有被重写的父类的构造函数都不能被访问
原因:父类的构造函数无法完成分配空间和设置初始值的工作
Person 重载了构造函数之后 override init,分配了name的值,所以实例化的时候可以使用 init()
Student 重载了构造函数之后 没有 override init,实例化时无法确认age的值,所以无法使用 init()
![](https://img.haomeiwen.com/i2974330/8257ca74c1506a1d.png)
![](https://img.haomeiwen.com/i2974330/33a465854f1bbc42.png)
KVC构造函数(overload)
class 继承 NSObject 才有 KVC 方法
因为 swift 中没有 runtime,所以不建议使用 KVC
原生支持的 json 转 model 是 Codable
KVC 的 Model 使用必选属性,给予默认值
所有参数前面加 @objc 或 在类前面加 @objcMember
class model: NSObject {
@objc var name: String?
@objc var age: Int = 0
init(dic: [String: Any]) {
super.init()
setValuesForKeys(dic)
}
// override class func setValue(_ value: Any?, forKeyPath keyPath: String) {
// super.setValue(value, forKeyPath: keyPath)
// }
//
// override func setValue(_ value: Any?, forUndefinedKey key: String) {
// print(key)
// }
}
便利构造函数
convenience
本身不负责创建对象,只是在init的外面添加了过滤条件,可能会创建失败返回nil。
只有便利 convenience 的构造函数中才能以 self.init 的形式访问指定的构造函数。
在分类中不能够定义指定的构造函数,必须使用便利构造函数
条件判断,只有满足条件,才实例化对象,可以防治造成不必要的内存开销。
便利构造函数具有以下特点:
- 可以构造失败 返回 nil,
- 只有便利构造函数中可以调用 self.init()
- 必须调用同一类中定义的其他指定构造函数或者用 self. 的方式调用父类的便利构造函数
- 便利构造函数不能被重写或者 super
convenience init?(name: String, age: Int) {
// 加拦截条件
if age < 20 || age > 100 {
return nil
}
// 指定初始化方法
self.init(dict: ["name": name, "age": age])
// 加工
self.name = "zhangsan"
}
其他
必要构造器
实现其他构造器方法时必须要修改的默认构造器,如:UIViewController 的 init(coder:)
逐一构造器
官方文档中提到,结构体如果没有定义任何自定义构造器,它们将自动获得逐一成员构造器(memberwise initializer)。不像默认构造器,即使存储型属性没有默认值,结构体也能会获得逐一成员构造器。
struct Size {
var width = 0.0, height = 0.0
}
let twoByTwo = Size(width: 2.0, height: 2.0)
// Swift 5.1 甚至会为你生成省去了有默认值属性的逐一构造器。省去的属性将会直接使用默认值
let zeroByTwo = Size(height: 2.0)
let twoByZero = Size(width: 2.0)
某些场景下,如果确实需要自定义一个构造器,但又想保留逐一成员构造器,那么请在 extension 中自定义构造器。
不过对于类来说,所有的构造器都必须自己来实现。所以从使用便利性的角度来说,结构体无疑是一个更好的选择。
可失败构造器
在 Swift 中可以定义一个构造器可失败的类,结构体或者枚举。这里的“失败”指的是,如给构造器传入无效的形参,或缺少某种所需的外部资源,又或是不满足某种必要的条件等。
为了妥善处理这种构造过程中可能会失败的情况。你可以在一个类,结构体或是枚举类型的定义中,添加一个或多个可失败构造器。其语法为在 init 关键字后面添加问号(init?)。比如 Int 存在如下可失败构造器:
init?(exactly source: Float)
参考资料:
由一个Crash引发对 Swift 构造器的思考
网友评论