Swift学习笔记之初始化
来源:互联网 发布:龙梅子专辑红颜知已 编辑:程序博客网 时间:2024/04/28 15:09
阶段构造
Swift 的构造过程分为两个阶段:
- 第一个阶段,每个存储型属性通过引入自己的构造器来设置初始值。
- 第二个阶段,在新实例准备使用之前进一步定制存储型属性。
安全检查
在构造的过程中, Swift 会进行四种安全检查。
安全检查 1
指定构造器必须保证它所在类引入的所有属性都必须先初始化完成,之后才能将其它构造任务向上代理给父类中的构造器。
比如下面这段代码就是错误的:
class Food { var name: String init(name: String) { self.name = name }}class RecipeIngredient: Food { var quantity: Int init(name: String, quantity: Int) { super.init(name: name) // ERROR! self.quantity = quantity }}
安全检查 2
指定构造器必须先向上代理调用父类构造器,然后再为继承的属性设置新值。如果没这么做,指定构造器赋予的新值将被父类中的构造器所覆盖。
比如下面这段代码就是错误的:
class Food { var name: String init(name: String) { self.name = name }}class RecipeIngredient: Food { override init(name: String) { self.name = "WHY" // ERROR! super.init(name: name) }}
安全检查 3
便利构造器必须先代理调用同一类中的其它构造器,然后再为任意属性赋新值。如果没这么做,便利构造器赋予的新值将被同一类中其它指定构造器所覆盖。
比如下面这段代码就是错误的:
class Food { var name: String init(name: String) { self.name = name }}class RecipeIngredient: Food { var quantity: Int init(name: String, quantity: Int) { self.quantity = quantity super.init(name: name) } override convenience init(name: String) { quantity = 2 // ERROR! self.init(name: name, quantity: 1) }}
安全检查 4
构造器在第一阶段构造完成之前,不能调用任何实例方法、不能读取任何实例属性的值,也不能引用 self 的值。
比如下面这段代码就是错误的:
class Food { var name: String init(name: String) { self.name = name }}class RecipeIngredient: Food { var quantity: Int init(name: String, quantity: Int) { self.quantity = quantity println(self.name) // ERROR! super.init(name: name) } override convenience init(name: String) { self.init(name: name, quantity: 1) }}
蛋疼的初始化过程
Swift 的初始化过程十分严格,刚从 OC 转过来的同仁可能习惯性的就写了这样的代码:
class ViewController: UIViewController { private let animator: UIDynamicAnimator required init(coder aDecoder: NSCoder) { // ERROR: Property 'self.animator' not initialized at super.init call super.init(coder: aDecoder) animator = UIDynamicAnimator(referenceView: self.view) }}
是的它报错了!哦想起来了,要在 super 前面初始化自己的属性:
class ViewController: UIViewController { private let animator: UIDynamicAnimator required init(coder aDecoder: NSCoder) { // use of property 'view' in base object before super.init initializes it animator = UIDynamicAnimator(referenceView: self.view) super.init(coder: aDecoder) }}
是的它又报错了!哦想起来了你不能在 view 的父类初始化之前调用这个属性。那就先不赋值吧:
class ViewController: UIViewController { private let animator: UIDynamicAnimator required init(coder aDecoder: NSCoder) { animator = UIDynamicAnimator() super.init(coder: aDecoder) // ERROR: Cannot assign to the result of this expression animator.referenceView = self.view }}
坑爹啊不是,这个属性居然是只读的!
我们只好把属性设置成 var
的可选类型,并且把初始化放到了 viewDidLoad
里面:
class ViewController: UIViewController { private var animator: UIDynamicAnimator? required init(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } override func viewDidLoad() { super.viewDidLoad() animator = UIDynamicAnimator(referenceView: self.view) }}
这时 animator
终于可以安全的访问 self.view
这个属性了。
你以为这就完了?想太多。
由于是可选类型,所以在使用的时候需要解包:
if let actualAnimator = animator { actualAnimator.addBehavior(UIGravityBehavior())}
这太丑了,或者用强制解包:
animator!.addBehavior(UIGravityBehavior())
或者用可选链:
animator?.addBehavior(UIGravityBehavior())
都!太!low!了!
这时候不妨试试隐式解析可选类型:
class ViewController: UIViewController { private var animator: UIDynamicAnimator! required init(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } override func viewDidLoad() { super.viewDidLoad() animator = UIDynamicAnimator(referenceView: self.view) }}
似乎好看多了。不过这并不是正确的打开方式,我觉得设计可选类型的工程师们应该不希望我们用这个方法,毕竟这更像是为了解决历史遗留包袱所做的妥协。
或许用 lazy
延时加载更合适:
class ViewController: UIViewController { lazy private var animator: UIDynamicAnimator = { return UIDynamicAnimator(referenceView: self.view) }() required init(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } override func viewDidLoad() { super.viewDidLoad() animator.addBehavior(UIGravityBehavior()) }}
References
- Initialization
- Deinitialization
- SWIFT INITIALIZATION AND THE PAIN OF OPTIONALS
- Swift学习笔记之初始化
- 初始化—Swift学习笔记(十七)
- 学习Swift笔记 (十六)Swift的初始化
- Swift学习之路02-类,初始化
- Swift学习笔记之数据类型
- Swift 学习笔记之基础
- Swift学习笔记之函数
- Swift学习笔记之习题
- Swift学习笔记之枚举
- swift学习笔记之数据类型
- Swift学习笔记之数组
- Swift学习笔记之函数
- Swift学习笔记之枚举
- Swift学习笔记之基础知识
- swift学习笔记之继承
- swift学习笔记之枚举
- smmu 学习笔记 之初始化
- swift语言的学习笔记十二(初始化方法)
- PHP检查端口是否可以被绑定
- python,PIL给图片加水印
- 关于vc的工具提示
- (贪心)zoj1360 Radar Installation 解题报告
- 安装cocoapods以及运行
- Swift学习笔记之初始化
- 【0123】 mysql的执行计划
- extjs grid的相关属性配置
- 说说我的第一次面试
- 阴影边框设置部分
- 两个队列模拟一个堆栈
- Java 服务提供框架
- dede关于上传图片失败和无法上传图片的两个错误
- c1