美文网首页程序员
Swift构造方法

Swift构造方法

作者: 奔跑的鸿 | 来源:发表于2020-07-19 15:51 被阅读0次
    • 构造方法作用:对实例对象的内容进行初始化
      Swift要求类或者结构体中的存储属性(非lazy属性)在对象构造完毕后要有初始化值
      语法:
    init(参数列表){ 初始化代码 }
    

    注意

    1. 构造方法的作用仅仅是用于初始化属性, 而不是分配内存, 分配内存是系统帮我们做的
    2. 构造方法是隐式调用的, 通过类名称() 形成创建一个对象就会隐式调用 init() 构造方法
    3. 如果所有的存储属性都有默认值, 可以不提供构造方法, 系统会提供一个隐式的构造方法;
    4. 如果存储属性可以提供默认值, 那么提倡大家使用设置默认值的方法, 这样可以简化代码,不用写构造方法
    class Person {
        var name: String = "hjq"
    //    var age: Int = 20
        var age:Int
        func description() -> String {
            return "name = \(name) age = \(age)"
        }
    
        init() {
            print("init")
            age = 30
        }
    }
    
    // 1.分配内存; 2.初始化name和age; 3.构造方法是隐式调用的
    var p = Person()
    print(p.description())
    print(p.age)
    
    • 带参数的构造方法
    class Person2 {
        var name:String
        var age:Int
        func description() -> String {
            return "name = \(name) age = \(age)"
        }
       
        init(age:Int, name:String)
        {
            self.name = name
            self.age = age
        }
        func setName(name:String, age:Int)
        {
            self.name = name
            self.age = age
        }
    }
    var p2 = Person2(age: 25, name: "hjq")
    p2.setName(name: "hjq", age: 30)
    print(p2.description())
    

    以上存储属性都没有提供默认值,必须提供构造方法,而构造方法是带参数的,所以创建对象时必须带参数来初始化存储属性,而不能用Person2()

    • 结构体和构造方法
    struct Rect {
        var width:Double
        var height:Double
        /*
        // 系统默认会提供一个类似的方法
        init(width:Double, height:Double)
        {
            self.width = width
            self.height = height
        }
        */
    }
    var r = Rect(width: 20, height: 20)
    

    以上存储属性都没有默认值,故必须用默认的逐一构造器初始化结构体,不存在Rect()的方式初始化结构体。
    如果在结构体中自定义了构造方法, 那么系统不会生成默认的逐一构造器。
    如果给存储属性提供了默认值, 系统还是会提供默认的逐一构造器

    • 构造器代理: 构造方法之间的相互调用,即在构造方法中可以调用其他构造方法来完成实例的构造。好处减少不必要的代码
    struct Rect2 {
        var width:Double, height:Double
        init(width:Double, height:Double)
        {
            self.width = width
            self.height = height
        }
        init()
        {
    //        self.width = 0.0
    //        self.height = 0.0
            //构造器代理
            self.init(width: 0, height: 0)
        }
        func show()
        {
            print("width = \(width) height = \(height)")
        }
    }
    var r2 = Rect2()
    r2.show()
    var r3 = Rect2(width: 100, height: 100)
    r3.show()
    
    • 指定构造器与便利构造器
      • 结构体是值类型,类是引用类型。引用类型的init()方法前必须加convenience关键字,这样的构造器被称为便利构造器。而带参数的init(name:String, age:Int)方法被称为指定构造器。
      • 便利构造器中必须出现self.init。
      • 指定构造器和便利构造器不能是相同参数
    class Person {
        var name:String
        var age:Int
        //指定构造方法都是以init开头
        init(name:String, age:Int)
        {
            self.name = name
            self.age = age
        }
        //1.如果是值类型没问题, 称之为构造器代理;
        //2.但是如果是引用类型会报错, 需要在前面加上 convenience关键字;
        //3.被convenience关键字修饰的构造方法称之为便利构造器, 通过调用其他构造方法来初始化;
        //4.反而言之, 便利构造器中一定是调用其他构造方法初始化的, 一定要出现self.init
        convenience init()
        {
            self.init(name: "hjq", age: 26)
        }
        //类可以拥有多个构造方法
        init(name:String)
        {
            self.name = name
            self.age = 0
            //不能再指定构造方法中调用便利构造器方法
            //换言之,指定构造方法中不能出现self.init
    //        self.init()
        }
        
        convenience init(age:Int)
        {
            //可以在便利构造器中调用指定构造器
    //        self.init(name: "hjq", age: 24)
            self.init()
        }
        // 便利构造器不能和指定构造器同名
        //    convenience init(name:String)
        //    {
        //    }
    }
    
    • 派生类的构造方法
    class Man {
        var name:String
        //指定构造器
        init(name:String)
        {
            self.name = name
        }
        convenience init(){
            self.init(name: "hjq")
        }
    }
    class SuperMan: Man {
        var age:Int
        
        // 注意:
        // 1.默认情况下基类的构造方法不会被继承
        // 2.基类的存储属性只能通过基类的构造方法初始化
        // 3.初始化存储属性时必须先初始化当前类再初始化父类
        // 4.不能通过便利构造器初始化父类, 只能通过调用指定构造器初始化父类
        //指定构造器
        init(age:Int) {
            self.age = age
            super.init(name: "han")    //必须调用父类的指定构造器
    //        super.init()    //不能调用父类的便利构造器
        }
    }
    
    • 构造器间的调用规则
      • 1.子类指定构造器必须调用其直接父类的"指定构造器"
      • 2.子类便利构造器必须调用当前类中的其他构造器(指定或者便利),且最终必须调用一个指定构造器结束(无论指定还是便利, 最终肯定调用一个指定构造器)
      • 3.子类指定构造器必须出现super.init,便利构造器不要super.init
    class Man2 {
        var name:String
        //指定构造器
        init(name:String) {
            self.name = name
        }
        convenience init(){
            self.init(name: "HaRi")
        }
    }
    class SuperMan2: Man2 {
        var age:Int
        //指定构造器
        init(age:Int) {
            self.age = age
            super.init(name: "xiaohange")
        }
        convenience init()
        {
            self.init(age: 25)
        }
        convenience  init(name: String, age: Int) {
            //调用当前类构造器一定能够初始化所有属性
    //        self.init(age: 30)
            //便利构造器中只能通过self.init来初始化, 不能使用 super.init
            //因为调用父类构造器不一定完全初始化所有属性(子类持有)
    //        super.init(name: "han")
            self.init()
        }
    }
    
    • 两段式构造。构造过程可以划分为两个阶段:
      1.确保当前类和父类所有存储属性都被初始化
      2.做一些其他初始化操作
      好处:可以防止属性在被初始化前访问
    class Man3 {
        var name:String
        //指定构造方法
        init(name:String) {
            self.name = name
        }
        //便利构造方法
        convenience init(){
            self.init(name: "hello world")
        }
    }
    
    class SuperMan3: Man3 {
        var age:Int
        init(age:Int) {
            print("SuperMan第一阶段开始")
            //对子类引入的属性初始化
            self.age = age
            
            //代码会报错, 因为调用self.name之前还没有对父类的name进行初始化
            //即便在这个地方修改, 也会被后面的初始化语句覆盖
    //        if age > 30 {
    //            self.name = "hjq"
    //        }
            //对父类引入的属性进行初始化
            super.init(name: "han")
            
            print("SuperMan第二阶段开始")
            if age > 30 {
                self.name = "hello xiaohange"
            }
        }
    }
    
    • 必须构造器。父类构造器加了required关键字,则子类必须重写该构造器,且带上required关键字
    class Person7 {
        var name:String
        required init(name:String){
            self.name = name
        }
    }
    class SuperMan7: Person7 {
        var age:Int
        init() {
            self.age = 24
            super.init(name: "hjq")
        }
        required init(name: String) {
            self.age = 24
            super.init(name: name)
        }
    }
    var sm7 = SuperMan7(name: "hjq")
    

    相关文章

      网友评论

        本文标题:Swift构造方法

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