美文网首页
Swift的初始化器

Swift的初始化器

作者: Sweet丶 | 来源:发表于2022-08-12 17:13 被阅读0次

上两篇 Swift中的属性Swift中的方法、继承

结构体和类的初始化.png
一、结构体的初始化器
/* 结构体初始化器
 1.编译器会自动生成包含所有存储属性的初始化器,
   如果该属性是有初始值的,那么生成的初始化器对应的参数也带初始值,在初始化时可以不传该参数
 2.自定义初始化器后,编译器不会生成其它初始化器
 3.可失败初始化器用init?和init!开头,用法参考类中
 */
struct ZLFrame {
    var height = 0
    var width = 0
    var x: Double = 1
    var y: Double = 1
    var rotateAngleY: Double
    
    // 自定义初始化器后,编译器不会生成其它初始化器
    init(isRatate: Bool) {
        rotateAngleY = isRatate ? Double.pi : 0
    }
}
二、类的初始化器

类的初始化器中规则有很多,但是都是围绕“初始化器调用完,所有存储属性必须有值”来进行的。

/* 一、类的两段式初始化:
 第一段:在初始化器中初始化完自身类中的存储属性和父类的存储属性。
 第二段:在第一段完成后才能用self去调方法、访问属性 */

/* 二、类的指定初始化器(designated initializer)
 0.类至少要有一个指定初始化器,指定初始化器是初始化实例对象的方式。
 1.当没有自定义指定初始化器时,编译器会自动生成默认指定初始化器(不带参数的init);当自定指定初始化器后,不生成默认的。
 2.指定初始化器调用完毕,所有成员必须有值,不需要写返回self, 调用完会自动返回。
 3.可以通过两种方式初始化:className(var1, var2,...)和className.init(var1, var2,...)
 4.可失败初始化器用init?和init!开头,初始化了一个可选类型的实例,也是一种指定初始化器;
 5.required用来修饰指定初始化器时,子类必须实现它,并且子类中也要加required,子类不用写override。
 6.convenience修饰的初始化器是便捷初始化器
 7.反初始化器在实例销毁前调用,并且不能手写super.deinit(),系统会自动在调用完自身deinit后调用父类的deinit。
 */
class HBA {
    var name: String
    var no: String
    // 1.当自定义了初始化器之后,默认的初始化器就没有了
    // 可以通过两种方式初始化:className(var1, var2,...)和className.init(var1, var2,...)
    /* required */ init(no: String, name: String) {
        self.no = no
        self.name = name
    }

    // 2.可失败初始化器, 外部调用时生成的可选类型的实例
    init?(no: String) {
        if no.isEmpty { return nil }
        self.no = no
        self.name = no + "big"
    }
    
    // 3.带隐式解包的可失败初始化器
    // a.在外部使用时与init?效果一样,都是生成可选类型实例,且使用上没有区别。
    // b.与init?的区别在于:在便捷初始化器中调用时,如果是init!可以不用自己在后面加"!"
    init!(name1: String) {
        if name1.isEmpty { return nil }
        self.name = name1
        self.no = "\(Int(name1) ?? 0)"
    }
    
    // 4.便捷初始化器
    // a.便捷初始化器中必须调用指定初始化器(可以是可失败初始化器)
    // b.在调用初始化器之后才能调用实例方法,即要保证实例的第一段初始化完成后再调用方法(二段式初始化)
    // c.如果调用了多次指定初始化器,最后那次的初始化才是真正返回给外部的实例
    // d.便捷初始化器可以调用其它便捷初始化器
    convenience init(local: Bool) {
        // 如果调用可失败初始化器,需要进行解包。
        // 下面两行是等价的,且运行时都会奔溃,因为初始化返回的是nil却进行解包了
        self.init(name1: "111")
        self.init(no: "222")!
        // 最终返回给外部的实例是最后调用的指定初始化器
        self.init(no: "23", name: "James")
        self.test1111()
    }
    
    // 5.便捷初始化器也可以是可失败的,这样在调用可失败初始化器时不需要解包
    convenience init?(net: Bool) {
        // 因为这里是便捷可失败初始化器,所以调用可失败指定初始化器不需要进行解包,调用的是带隐式解包的也不会有风险因为没有进行解包
        self.init(name1: "")
        self.test1111()
    }
    
    func test1111() {
        print("test1111----")
    }
    
    // 6.反初始化器,在实例销毁时调用
    // a.不能手写super.deinit(),系统会自动在调用完自身deinit后调用父类的deinit。
    deinit {
        print("HBA.deinit------")
    }
}

子类中初始化器

/* 子类的初始化器
 0.如果子类中所有存储属性都有默认值或者根本没有自己的存储属性,那么有:
   a.在不自定义指定初始化器时,会自动继承父类所有的指定初始化器+便捷初始化器。
   b.在有自定义指定初始化器时,不再继承父类的所有初始化器。
 1.子类中有存储属性没有默认值时,必须要有自定义初始化器
 2.自定义初始化器中必须在自己属性都有值后再调用父类的指定初始化器,并且实例调用方法必须在super.init之后。
 3.如果子类实现了父类所有指定初始化器,那么会自动继承便捷初始化器。
 4.子类重写父类指定初始化器时要加override
 5.子类必须实现父类required修饰的初始化,并用required修饰,不用写override。
 6.子类的便捷初始化器方法中不能调用父类的便捷、指定初始化器
 7.子类重写父类的便捷初始化器不用加override,因为不能调用super,本质上还是自己的方法,也就不存在重写的说法
 */
class ZHXL: HBA {
    var var1 : String
    var var2 : Bool = false
    
    // 1.子类自定义初始化器后,不会继承父类初始化器;
    // 需要在自己属性都有值后,再调用父类的指定初始化器;实例方法需要在两段式初始化的第一段完成后调用
    init(var1: String) {
        self.var1 = var1
        super.init(no: "XLXL666", name: "纵横小拉")
//        super.init(no: "233")!
        // 这个self.test222()不能在super.init调用之前调用
        self.test1111()
    }

    // 2.子类便捷初始化器不能调用父类的指定、便捷初始化器
    convenience init(var1: String, var2: Bool) {
        self.init(var1: "var1")
        self.var2 = var2
    }
    
    // 3.子类必须实现父类的required指定初始化器
    // 如果父类没写required,自己类中也可以写required要求子类必须实现,并且自身类中要加override表明是重写
    required override init(no: String, name: String) {
//        fatalError("init(no:name:) has not been implemented")
        self.var1 = "null"
        super.init(no: no, name: name)
    }
}

相关文章

网友评论

      本文标题:Swift的初始化器

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