美文网首页
swift初始化 init

swift初始化 init

作者: SwiftDev | 来源:发表于2019-07-25 15:53 被阅读0次

    swift初始化器有两种:

    • 指定初始化器(designated initializer)
    • 便捷初始化器(convenience initializer)

    初始化器的一些特点:

    • 每个类至少有一个初始化器
      • 自己没有添加初始化器的话,编译器会自动添加init(){ }
      • 一旦自己实现了指定初始化器的话,编译器就不会自动添加 init(){ }
    • 官方建议 类使用少量指定初始化器

    初始化器的调用规则:

    • 指定初始化器必须从他的直系父类调用初始化器(安全:保证父类的初始化完成)
      • 同一个类中,多个指定初始化器之间不能相互调用
    • 便捷初始化器必须从相同的类里调用另一个初始化器
      • 不能调用父类的初始化器,只能横向调用
      • 多个便捷初始化器,可以相互调用
    • 便捷初始化器最终必须调用一个指定初始化器(这样做事为了安全,不管使用哪种方式创建,都必须走初始化代码)
      • 便捷初始化器只能且必须调用自己的初始化器,不能调用父类的初始化器

    下图是初始化器之间的相互调用关系:


    image.png

    这样保证了,使用任意初始化器,都可以完整的初始化实例

    两段式初始化

    第一阶段:初始化所有成员

    • 初始化自己的所有成员变量
    • 调用父类的初始化方法,初始化父类的成员变量,如果还有父类,一层层向上调用

    调用如下图:


    image.png

    第二阶段

    • 对属性设置新值(例如对父类的成员变量赋值)
      • 只有第一阶段完成,即初始化结束,才能使用 self 访问、修改成员变量或者调用他的实例方法

    这个调用是从上到下的如图:

    image.png

    一个完整的初始化过程从上到下:


    image.png

    总结:苹果做的安全检查

    • 指定初始化器必须在调用父类初始化之前,给自己所有成员变量赋值
    • 指定初始化器必须先调用父类的初始化器,然后才能为继承的属性赋值
    • 便捷初始化器必须先调用同类的其他初始化器,然后再为任意属性设值
    • 初始化器在第一阶段完成之前,不能调用任何实例方法,不能读取任何属性的值,不能 引用self

    override

    特点

    • 重写父类的指定初始化器,添加override
    • 子类实现跟父类相同的便捷初始化器,不需要添加override,
      • 重写的特点就是在子类中能否调用到父类的方法,而子类的便捷初始化器是调用不到父类的便捷初始化器的,严格来说,子类无法重写父类的便捷初始化器

    自动继承

    • 如果子类没有定义任何指定初始化器,它会自动继承父类所有的初始化器,自己不会在添加init(){}
      如图:
      image.png
    • 如果子类提供了父类所有的初始化器的实现(要么通过继承:上面自动继承的方式,要么重写)
      • 子类自动继承多有的父类便捷初始化器
    • 即使子类以便捷初始化器的形式重写指定初始化器,同样满足上面一条的规则
      如图:


      image.png

    举个反例:


    image.png

    required

    • 使用required修饰指定初始化器,其子类必须都实现该初始化器(继承或者重写)
    • 子类重写了required初始化器,也必须添加required,但是无需加override
    • 补充一点:required只对指定初始化器有效,便捷初始化器添加上也不会报错,只是没有用,原因很简单,便捷初始化器是横向调用的,没有子类继承父类这种

    属性观察器
    这里涉及到一个属性观察器的一个小知识点:
    属性观察器在自己的初始化中是不会被调用的,但是在子类中的初始化中,是会被调用的

    class Animal: NSObject  {
        var name: String {
            willSet {
                print("willSet: \(newValue)")
            }
            didSet {
                print("didSet: \(oldValue)")
            }
    
        }
        init(name: String) {
            self.name = name
            super.init()
        }
    }
    
    class Person: Animal {
        var height: Double
        init(height: Double) {
            self.height = height
            super.init(name: "jack")
            self.name = "rose"
        }
    }
    // 没有打印
    Animal(name: "swift")
    /*
     打印
     willSet: rose
     didSet: jack
     */
    Person(height: 19)
    
    

    可失败初始化器

    init?(){ } 
    
    

    允许初始化器为nil;calss,结构体,枚举 都可以定义可失败初始化器

    Int("xxxx") 
    public init?(_ description: String)
    
    

    这个就是可失败初始化器

    deinit

    deinit 类似于OC中的dealloc,内存释放的时候调用

    class Aniaml {
        deinit {
            print("对象销毁了")
        }
    }
    
    

    父类的deinit可以被继承;
    子类的deinit调用完成后会在调用父类的deinit

    相关文章

      网友评论

          本文标题:swift初始化 init

          本文链接:https://www.haomeiwen.com/subject/outrlctx.html