Swift 基础学习(指定构造方法和便利构造方法)

/*
   继承与构造方法
(1)指定构造与便利构造方法解析
(2)派生类的构造方法
(3)构造器链和安全检查深入解析
(4)派生类的构造方法默认继承
(5)构造方法的重写
(6)必须构造方法
(7)析构方法
*/

/*
(1)指定构造与便利构造方法解析(Designated Initializers and Convenience Initializers)
*/
class AB {
    var a: Int
    var b: Int
    //指定构造方法, 不允许出现构造器代理,self.init(...)
    init(a: Int, b: Int) {
        self.a = a
        self.b = b
        print("Class AB init!")
    }

    //便利构造方法 -> 一定是通过调用其他的构造方法来实现初始化, self.init(...)
    convenience init(a: Int) {
//        self.a = a
//        b = 0
        self.init(a: a, b: 0)
    }
    convenience init() {
        //调用指定构造方法
//        self.init(a: 0, b: 0)
        //调用便利构造方法
        self.init(a: 0)
    }
}

/*
(2)派生类的构造方法
*/
class CD: AB {
    var c: Int
    var d: Int
    //构造方法默认是不会被继承,基类的存储属性只能通过基类的构造方法来初始化
    //派生类引入的存储属性要先被初始化,然后再调用父类的构造方法对父类的属性进行初始化
    //我们只能通过调用父类的指定构造方法来对父类的属性进行初始化
    init(c: Int, d: Int) {
        self.c = c
        self.d = d
        super.init(a: 0, b: 0)
//        super.init(a: 0)
    }
}

/*
(3)构造器链-指定构造器和便利构造器之间的调用规则
总结:1.指定构造器必须调用其直接父类的指定构造器
    2.便利构造器必须调用同类中定义的其他构造器.(既可以是
指定构造器,也可以是便利构造器)
    3.便利构造器必须最终以调用一个指定构造器结束
指定构造器总是向上代理
便利构造器总是横向代理
*/
class CD1: AB {
    var c: Int
    var d: Int

    //指定构造器
    init(c: Int, d: Int) {
        self.c = c
        self.d = d
        super.init(a: 0, b: 0)
        //        super.init(a: 0)
    }
    //便利构造器, 只能通过调用本类中的构造器完成初始化,不允许出现super.init(...)
    convenience init(a: Int, b: Int, c: Int, d: Int) {
        self.init(c: c, d: d)

    }
}

/*
(4)两段式构造-构造过程可以划分为两个阶段
第一阶段:确保所有的存储属性都初始化完毕
第二阶段:对父类中的存储属性做进一步的处理.
作用:可以防止属性在被初始化之前访问,也可以防止属性被另外
一个构造器意外的赋值.
*/
class A {
    var a: Int
    init(a: Int) {
        self.a = a
    }
}
class B: A {
    var b: Int
    init(a: Int, b: Int) {
        //派生类引入的属性进行初始化
        print("类B第一阶段初始化开始")
        self.b = b
        //父类的指定构造方法对父类的属性进行初始化
        //只能在第一阶段之后才能够访问
//        self.a = 1000
        super.init(a: a)

        print("类B第二阶段初始化开始")
        if (b > 100) {
            self.a = 1000
        }
    }
}
class C: B {
    var c: Int
    init(a: Int, b: Int, c: Int) {
        //派生类引入的属性进行初始化
        print("类C第一阶段初始化开始")
        self.c = c
        //父类的指定构造方法对父类的属性进行初始化
        super.init(a: a, b: b)

        print("类C第二阶段初始化开始")
        if (c > 1000) {
            self.a = 1000
            self.b = 1000
        }
    }
}
class D: C {
    var d: Int
    init(a: Int, b: Int, c: Int, d: Int) {
        //派生类引入的属性进行初始化
        print("类D第一阶段初始化开始")
        self.d = d
        //父类的指定构造方法对父类的属性进行初始化
        super.init(a: a, b: b, c: c)

        print("类D第二阶段初始化开始")
        if (d > 1000) {
            self.a = 1000
            self.b = 1000
            self.c = 1000
        }
    }
}
var d = D(a: 0, b: 0, c: 0, d: 0)

/*
(5)派生类构造方法定义时的编译器安全性检查
a 首先应该将派生类引入的存储属性初始化,然后再向上代理父类
的制定构造方法.
b 首先调用父类中的制定构造器实现父类中属性的初始化之后,才
可以访问父类中的属性.
c  在编写便利构造方法时,我们首先要调用同类中的其他构造方
法,然后才可以访问
d  在第一阶段完成之前,不能调用任何实例方法,不能访问任何
父类中定义的存储属性,也不能引用self
*/
class D1: C {
    var d: Int
    init(a: Int, b: Int, c: Int, d: Int) {
        //派生类引入的属性进行初始化
        print("类D第一阶段初始化开始")
        self.d = d
        //父类的指定构造方法对父类的属性进行初始化
        /*
        (1)不可以访问父类中的属性
        (2)不可以调用成员方法
        */
//        self.test()
        super.init(a: a, b: b, c: c)

        print("类D第二阶段初始化开始")
        if (d > 1000) {
            self.a = 1000
            self.b = 1000
            self.c = 1000
        }
    }
    convenience init() {
        //首先应该调用同类中的其他构造方法之后,才可以访问属性
        self.init(a: 0, b:0, c: 0, d:0)
        a = 9
        b = 3
        c = 4
        d = 90
    }
    func test() {

    }
}

/*
(6)重写指定构造方法
是指"子类中构造方法与父类中的构造方法的参数列表一模一样"
*/
class Human {
    let name: String
    var age: Int
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
}
class Woman: Human {
    var haveBaby: Bool = false
    //派生类中定义一个构造方法,它跟父类中的某个指定构造方法一样
//    override init(name: String, age: Int) {
//        haveBaby = false
//        super.init(name: name, age: age)
//    }

    init(name: String, age: Int, haveBaby: Bool) {
        self.haveBaby = false
        super.init(name: name, age: age)
    }
    convenience override init(name: String, age: Int) {
        self.init(name: name, age: age, haveBaby: false)
    }
}

/*

(7)重写便利构造方法(其余便利构造方法不存在重写,只是为了和上面的做对比,才起的这样名)

*/
class Human1 {
    let name: String
    var age: Int
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
    convenience init() {
        self.init(name:"", age: 0)
    }
}
class Woman1: Human1 {
    var haveBaby: Bool = false
    //重写成一个指定构造方法, 需要加上override关键字
    override init(name: String, age: Int) {
        haveBaby = false
        super.init(name: name, age: age)
    }
    //重写一个便利构造方法,也需要加上override关键字
//    convenience override init(name: String, age: Int) {
//        self.init(name: name, age: age, haveBaby: false)
//    }

    init(name: String, age: Int, haveBaby: Bool) {
        self.haveBaby = false
        super.init(name: name, age: age)
    }
    convenience  init() {
        self.init(name: "" , age: 0, haveBaby: false)
    }
}
var w0 = Woman1()

/*
(8)构造器的自动继承
a. 如果子类中没有定义任何的构造方法,且子类中所有的存储属
性都有默认缺省值,会自动继承父类中所有的构造方法(包括便利
构造方法);
b. 如果子类中只是重写了父类中的某些(而不是全部)指定构造
方法,不管子类中的存储属性是否有缺省值,都不会继承父类中的
其他构造方法;
c. 如果子类中重写了父类中所有的指定构造方法,不管子类中的
存储属性是否有缺省值,都同时会继承父类中所有的便利构造方
法;
*/
class XY {
    var x: Int
    var y: Int
    init(x: Int, y: Int) {
        self.x = x
        self.y = y
    }
    init(x: Int){
        self.x = x
        self.y = 0
    }
    convenience init() {
        self.init(x: 0, y: 0)
    }
}
//对应上面的a结论,没有任何构造方法
class XYZ: XY {
    var z: Int = 10
    //对应上面的a结论,没有任何构造方法
//    init(z: Int) {
//        self.z = z
//        super.init(x: 0, y: 0)
//    }
}
//对应上面的b结论,只是重写部分构造方法
class XYZ1: XY {
    var z: Int = 10
    //    init(z: Int) {
    //        self.z = z
    //        super.init(x: 0, y: 0)
    //    }
    override init(x: Int, y: Int) {
        z = 10
        super.init(x: x, y: y)
    }

}
//对应上面的c结论,重写父类所有构造方法
class XYZ2: XY {
    var z: Int = 10
    override init(x: Int, y: Int) {
        z = 10
        super.init(x: x, y: y)
    }

    override init(x: Int) {
        z = 10
        super.init(x: x, y: 0)
    }

}

var t0 = XYZ()
var t1 = XYZ2(x: 0)
var t2 = XYZ1(x: 0, y: 0)
print(t0.z)
print(t1.z)
print(t2.z)

/*
(9)必须构造器,构造方法所属的类的后续子类必须也得实现这个构造方法
*/
class Some {
    var some: Int
    //必须实现方法
    required init() {
        some = 0
    }
}
class ChildOfSome: Some {
    var sub: Int
    init(sub: Int) {
        self.sub = sub
        super.init()
    }
    //子类也必须实现该方法
    required init() {
        sub = 0
        super.init()
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Swift中的构造器是用来创建和初始化对象的特殊方法。在Swift中,类、结构体和枚举都可以定义构造器构造器的主要作用是为对象的存储属性设置初始值。 在Swift中,构造器的基本语法如下: ``` init() { // 构造器的实现代码 } ``` 在构造器中,可以使用self关键字来引用当前对象,也可以使用属性名来引用对象的属性。在构造器中,必须为对象的所有存储属性赋值,否则会出现编译错误。 除了定义默认构造器,还可以定义带参数的构造器。带参数的构造器可以接收一个或多个参数,并根据参数的值来设置对象的属性。例如: ``` init(name: String, age: Int) { self.name = name self.age = age } ``` 在使用构造器创建对象时,可以根据需要选择不同的构造器。例如,使用默认构造器创建一个对象: ``` let obj = MyClass() ``` 也可以使用带参数的构造器来创建对象: ``` let obj = MyClass(name: "Tom", age: 20) ``` 在Swift中,还可以使用可失败构造器来创建对象。可失败构造器可以在初始化过程中检查某些条件,如果条件不满足,则构造器返回nil。例如: ``` init?(name: String) { if name.isEmpty { return nil } self.name = name } ``` 使用可失败构造器创建对象时,需要使用可选类型来接收对象,因为构造器可能返回nil: ``` let obj = MyClass(name: "") if let obj = obj { // 构造器执行成功,obj不为nil } else { // 构造器执行失败,obj为nil } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值