Swift 指定初始化器和便捷初始化器

1、语法

  • 用与值类型的简单初始化器相同的方式来写类的指定初始化器
  • 用 convenience 修饰符放到 init 关键字前定义便捷初始化器
//类的初始化器
class Person {
    var name: String
    var age: Int
    //指定初始化器
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
    //便捷初始化器
    convenience init(age: Int) {  //便捷初始化器必须要先调用本类的指定初始化器
        self.init(name: "zhangsan", age: age)
    }
}

2、类的初始化委托

  • 指定初始化器必须从它的直系父类调用指定初始化器
  • 便捷初始化器必须从相同的类里调用另一个初始化器
  • 便捷初始化器最终必须调用一个指定初始化器
    如图:
    在这里插入图片描述

3、初始化过程(两段式初始化)

  • Swift 的类初始化是一个两段式过程。在第一个阶段,每一个存储属性被引入类分配了一个初始值。 一旦每个存储属性的初始状态被确定,第二个阶段就开始了,每个类都有机会在新的实例准备使用之 前来定制它的存储属性
  • 两段式初始化过程的使用让初始化更加安全,同时在每个类的层级结构给与了完备的灵活性。两段式初始化过程可以防止属性值在初始化之前被访问,还可以防止属性值被另一个初始化器意外地赋予不同的值

4、安全检查

  • 1、指定初始化器必须保证在向上委托给父类初始化器之前,其所在类引入的所有属性都要初始化完成。
  • 2、指定初始化器必须先向上委托父类初始化器,然后才能为继承的属性设置新值。如果不这样做, 指定初始化器赋予的新值将被父类中的初始化器所覆盖。
  • 3、便捷初始化器必须先委托同类中的其它初始化器,然后再为任意属性赋新值(包括同类里定义的 属性)。如果没这么做,便捷构初始化器赋予的新值将被自己类中其它指定初始化器所覆盖。
  • 4、初始化器在第一阶段初始化完成之前,不能调用任何实例方法、不能读取任何实例属性的值,也 不能引用 self 作为值
class Teacher: Person {
    var salary: Int
    init(name: String, age: Int, salary: Int) {
        self.salary = salary  //要先完成本类属性的初始化
        super.init(name: name, age: age)   //接着就是调用父类的指定初始化器(这是第一阶段)
        showInfo()   //调用实例方法,读取实例属性的值,引用 self 的值 都需要在第一阶段完成之后
        self.name = name + "老师"   //最后可以为继承过来的属性设置新值 (第二阶段)
    }
    convenience init(name: String) {
        //便捷初始化器必须要先调用本类的指定初始化器
        self.init(name: name, age: 20, salary: 5000)
        //才能设置其他属性的值
        self.name = name + "老师"
    }
    func showInfo() {
        print("teacher name \(name), age \(age), salary \(salary)")
    }
}
//let teacher = Teacher(name: "lisi", age: 34, salary: 6000)
let teacher = Teacher(name: "张三")
teacher.showInfo()

5、两段式初始化过程-阶段1

  • 1、指定或便捷初始化器在类中被调用;
  • 2、为这个类的新实例分配内存。内存还没有被初始化;
  • 3、这个类的指定初始化器确保所有由此类引入的存储属性都有一个值。现在这些存储属性的内存被初始化了;
  • 4、指定初始化器上交父类的初始化器为其存储属性执行相同的任务;
  • 5、这个调用父类初始化器的过程将沿着初始化器链一直向上进行,直到到达初始化器链的最顶部
  • 6、一旦达了初始化器链的最顶部,在链顶部的类确保所有的存储属性都有一个值,此实例的内存被认为完全初始化了,此时第一阶段完成。

6、两段式初始化过程-阶段2

  • 1、从顶部初始化器往下,链中的每一个指定初始化器都有机会进一步定制实例。初始化器现在 能够访问 self 并且可以修改它的属性,调用它的实例方法等等;
  • 2、最终,链中任何便捷初始化器都有机会定制实例以及使用 self 。

7、初始化器的继承和重写

  • 不像在 Objective-C 中的子类,Swift 的子类不会默认继承父类的初始化器。Swift 的这种机制防止父类的简单初始化器被一个更专用的子类继承并被用来创建一个没有完全或错误初始化的新实例的情况发生。只有在特定情况下才会继承父类的初始化器。
  • 如果你想自定义子类来实现一个或多个和父类相同的初始化器,你可以在子类中为那些初始化器提供定制的实现。
  • 当你写的子类初始化器匹配父类指定初始化器的时候,你实际上可以重写那个初始化器。因此,在子类的初始化器定义之前你必须写 override 修饰符。如同默认初始化器所描述的那样,即使是自动提供的默认初始化器你也可以重写

8、初始化器的自动继承

  • 如果你的子类没有定义任何指定初始化器,它会自动继承父类所有的指定初始化器。

9、结论

  • 所有类的存储属性(包括从它的父类继承的所有属性)都必须在初始化期间分配初始值。
  • Swift 为类类型定义了两种初始化器以确保所有的存储属性接收一个初始值。这些就是所谓的指定初始化器和便捷初始化器。
  • 指定初始化器是类的主要初始化器。指定的初始化器可以初始化所有那个类引用的属性并且调用合适的父类初始化器来继续这个初始化过程给父类链。
  • 类偏向于少量指定初始化器,并且一个类通常只有一个指定初始化器。
  • 每个类至少得有一个指定初始化器。
  • 便捷初始化器是次要的
  • 如果类不需要便捷初始化器可以不提供它。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值