摘要:Swift有着超级严格的初始化方法,不仅强化了designated初始化方法的地位,所有不加修饰的init方法都需要在方法中确保非Optional的实例变量被赋值初始化,而在子类中,也强制调用super版本的designated初始化。

我们在深入初始化方法之前,不妨先再想想Swift中的初始化想要达到一种怎样的目的。

其实就是安全。在Objective-C中,init方法是非常不安全的:没有人能保证init只被调用一次,也没有人保证在初始化方法调用以后,实例的各个变量都完成初始化,甚至如果在初始化里使用属性进行设置的话,还可能会造成各种问题。虽然Apple也明确说明了不应该在init中使用属性来访问,但这并不是编译器强制的,因此还是会有很多开发者犯这样的错误。

所以Swift有了超级严格的初始化方法。一方面,Swift强化了designated初始化方法的地位。Swift中不加修饰的init方法都需要在方法中保证所有非Optional的实例变量被赋值初始化,而在子类中也强制 (显式或隐式地)调用super版本的designated初始化,所以无论如何走何种路径,被初始化的对象总是可以完成完整的初始化的。

  1. class ClassA {
  2. let numA: Int
  3. init(num: Int) {
  4. numA = num
  5. }
  6. }
  7. class ClassB: ClassA {
  8. let numB: Int
  9. override init(num: Int) {
  10. numB = num + 1
  11. super.init(num: num)
  12. }
  13. }

在上面的示例代码中,注意在init里我们可以对let的实例常量进行赋值,这是初始化方法的重要特点。在Swift中let声明的值是不变量,无法被写入赋值,这对于构建线程安全的API十分有用。而因为Swift的init只可能被调用一次,因此在init中我们可以为不变量进行赋值,而不会引起任何线程安全的问题。

与designated初始化方法对应的是在init前加上convenience关键字的初始化方法。这类方法是Swift初始化方法中的“二等公民”,只作为补充和提供使用上的方便。所有的convenience初始化方法都必须调用同一个类中的designated初始化完成设置,另外convenience的初始化方法是不能被子类重写或从子类中以super的方式被调用的。

  1. class ClassA {
  2. let numA: Int
  3. init(num: Int) {
  4. numA = num
  5. }
  6. convenience init(bigNum: Bool) {
  7. self.init(num: bigNum ? 10000 : 1)
  8. }
  9. }
  10. class ClassB: ClassA {
  11. let numB: Int
  12. override init(num: Int) {
  13. numB = num + 1
  14. super.init(num: num)
  15. }
  16. }

只要在子类中实现重写了父类convenience方法所需要的init方法的话,我们在子类中就也可以使用父类的convenience初始化方法了。比如在上面的代码中,我们在ClassB里实现了init(num: Int)的重写。这样,即使在ClassB中没有bigNum版本的convenience init(bigNum: Bool),我们仍然还是可以用这个方法来完成子类初始化:

  1. let anObj = ClassB(bigNum: true)
  2. // anObj.numA = 10000, anObj.numB = 10001

因此进行一下总结,可以看到初始化方法永远遵循以下两个原则:

  1. 初始化路径必须保证对象完全初始化,这可以通过调用本类型的designated初始化方法来得到保证;
  2. 子类的designated初始化方法必须调用父类的designated方法,以保证父类也完成初始化。

对于某些我们希望子类中一定实现的designated初始化方法,我们可以通过添加required关键字进行限制,强制子类对这个方法重写实现。这样的一个最大的好处是可以保证依赖于某个designated初始化方法的convenience一直可以被使用。一个现成的例子就是上面的init(bigNum: Bool):如果我们希望这个初始化方法对于子类一定可用,那么应当将init(num: Int)声明为必须,这样我们在子类中调用init(bigNum: Bool)时就始终能够找到一条完全初始化的路径了:

  1. class ClassA {
  2. let numA: Int
  3. required init(num: Int) {
  4. numA = num
  5. }
  6. convenience init(bigNum: Bool) {
  7. self.init(num: bigNum ? 10000 : 1)
  8. }
  9. }
  10. class ClassB: ClassA {
  11. let numB: Int
  12. required init(num: Int) {
  13. numB = num + 1
  14. super.init(num: num)
  15. }
  16. }

另外需要说明的是,其实不仅仅是对designated初始化方法,对于convenience的初始化方法,我们也可以加上required以确保子类对其进行实现。这在要求子类不直接使用父类中的convenience初始化方法时会非常有帮助。

Swift中的init方法的更多相关文章

  1. Swift基础--Swift中的分类以及在分类中扩展init方法的注意事项

    Swift中的分类 1.创建一个空的swift文件 2.关键字extension,格式: extension 要扩展的类名 {} extension UIButton { } Swift中扩展init ...

  2. IOS开发中重写init方法使用需谨慎

    IOS开发中重写init方法使用需谨慎 今天在写一个小软件的时候出现一点问题,这个软件的功能是搜索全国学校,首页就是搜索输入框,在框中输入完要查询的学校所在省份,点击buttom后就会跳转到对应的视图 ...

  3. iOS开发之swift与OC混编出现的坑,oc中不能对swift的代理进行调用,不能访问swift中的代理,swift中的回调方法

    1. Swift与oc混编译具体怎么实现,这儿我就不重复讲出了,网上有大把的人讲解. 2. 在swift与OC混编的编译环境下, oc类不能访问swift创建类中的代理? 解决方法如下: 在代理的头部 ...

  4. Swift基础之init方法,实例方法,类方法(静态方法)的使用(多标签Demo)

    Xcode更新过后,有些方法都进行了改变,Demo中有变化的都进行了简单的标记,具体以后遇见再说 创建一个UIView类,用init方法创建两种类型,显示多标签,创建静态方法进行调用,创建类方法进行调 ...

  5. OC中自定义init方法

    ---恢复内容开始--- 我们知道,在函数中实例化一个对象,大多数会同时进行初始化,如 Person *p =[ [Person alloc]init]; 此时已经进行了初始化,使用init方法,那么 ...

  6. Swift新手教程系列5-函数+selector在swift中的使用方法

    原创blog.转载请注明出处 近期在用swift写代码,尽管遇到一些问题,可是代码量确实减了不少. swfit新手教程系列会随着我使用swfit中的积累,不断地去修正更新 之前的教程 swift单例模 ...

  7. Swift中自定义打印方法

    // 1.获取打印所在的文件 let file = ( #file as NSString).lastPathComponent // 2.获取打印所在的方法 let funcName = #func ...

  8. python中的Init方法, new 方法 call 方法

    new 方法实现单列模式思考 class Single: _single = None _single_only = None def __init__(self, value): self.v = ...

  9. python 子类中定义init方法

随机推荐

  1. PTA 计算平均值

    现在为若干组整数分别计算平均值. 已知这些整数的绝对值都小于100,每组整数的数量不少于1个,不大于20个. 输入格式:首先输入K(不小于2,不大于20).接下来每一行输入一组数据(至少有一组数据), ...

  2. 3DMAX 8 角色建模2 身体

    身体 20 25 60 分段 3 2 3 位置直接设置到-12.5 0 0,删除内部面,实例镜像出另一半x偏移25 1 身体大体形状 ,,,, 2 背阔肌 , 3腹肌 4 臀部 ,, 5 肩部 调整点 ...

  3. Unity局部高效实时阴影的思考和实现

    http://game.ceeger.com/forum/read.php?tid=23305&fid=2 无意间看到一篇文章,说是Unity5 demo中为了实现角色的良好阴影,单独给角色设 ...

  4. python iteration 迭代

    可迭代的类型:list,tuple,dict,str,bytes,bytearray等 一.怎么判断一个对象是否可迭代 >>> from collections import Ite ...

  5. elasticsearch 查询 query

    对于 类型是 text的字段,并且分析器指明是ik_max_word的会建立倒排索引 查询的分类: match查询:  会自动转换大小写,会分词, term查询: 不会转换和分词,只能值匹配 term ...

  6. jQuery笔记之位置图形

    位置图形: 位置坐标图形大小相关方法: .offset() .position() .scrollTop()..scrollLeft() .width().height() .innerWidth() ...

  7. 51Nod 1092 回文字符串

    最开始毫无头绪,然后参照了一位dalao的博客,思路是一个正序的字符串将其逆序,然后求最长公共子序列(LCS),emm也属于动态规划. #include <iostream> #inclu ...

  8. hdu6195 cable cable cable(from 2017 ACM/ICPC Asia Regional Shenyang Online)

    最开始一直想不通,为什么推出这个公式,后来想了半天,终于想明白了. 题目大意是,有M个格子,有K个物品.我们希望在格子与物品之间连数量尽可能少的边,使得——不论是选出M个格子中的哪K个,都可以与K个物 ...

  9. 如何用Python在10分钟内建立一个预测模型

    转载自:https://baijia.baidu.com/s?old_id=307995 最近,我从孙子(指<孙子兵法>——译者注)那里学到了一些策略:速度和准备 “兵之情主速,乘人之不及 ...

  10. LightOj 1076 - Get the Containers (折半枚举好题)

    题目链接: http://www.lightoj.com/volume_showproblem.php?problem=1076 题目描述: 给出n个数,要求分成m段,问这m段中最大的总和,最小是多少 ...