Swift基础 构造函数

指定构造函数

struct Person {
    init() {
        // 构造函数
    }
}
class Person {
    init() {
        // 构造函数
    }
}

如果在结构体中定义了属性,不用自己写构造函数,默认会有一个逐一成员构造函数。
如果在类中定义了属性(非可选),自己就得在构造函数对属性进行初始化赋值,构造函数必须写。

便利构造器

在Swift中,多了一个便利构造器,即在init前面加上“convenience”

struct Person {
    convenience init() {
        // 便利构造函数
        // 必须调用同类的指定构造函数(其中一个即可)
        self.init()
    }
}
class Person {
    convenience init() {
        // 便利构造函数
        // 必须调用同类的指定构造函数(其中一个即可)
        self.init()
    }
}

便利构造器有什么用呢,顾名思义嘛,就是为了便利。

3个规则

规则1: 指定构造器必须调用其直接父类的的指定构造器。
规则2: 便利构造器必须调用同类中定义的其他构造器。
规则3: 便利构造器必须最终导致一个指定构造器被调用。

其实和容易记住

指定构造器必须总是向上代理。
便利构造器必须总是横向代理。

2个阶段

Swift的构造过程分2个阶段:

阶段1:

(1)构造器被调用
(2)新实例分配内存,但内存还没初始化
(3)指定构造器中,先对所在的类引入的属性(特有的属性)赋初始值。
(4)指定构造器调用父类的构造器,对父类的属性赋初始值。
(5)沿着构造链,一直往上执行,(父类可能还有父类,继续调用父类的构造器),直到构造链的顶端。
(6)确保类所有属性(子类,父类所有的属性)都已经赋初始值,这就认为这个实例的内存已经完全初始化了,也就是可以使用了。阶段1完成。

注意了,阶段1中,因为实例还没完成初始化,不能调用任何实例方法,不能读取任何实例的值,也不能引用self作为值使用。(可以使用self赋值,如 self.name = name)

阶段2:

(1)顶端构造器开始往下执行,每个构造器都有机会定制实例。当然,因为实例已经初始化了,可以调用方法,也可以修改属性值,也可以使用self。
(2)最后,便利构造器也可以定制实例。

class RootClass {
    var a: Int
    init(a: Int) {
        self.a = a            // (3) ------------ 阶段1
        apple()               // (4) ------------ 阶段2
    }
    func apple() {
        print("a apple")
    }
}
class SonClass: RootClass {
    var b: Int
    init(b: Int) {
        self.b = b            // (2) ------------ 阶段1
        super.init(a: 1)
        banana()              // (5) ------------ 阶段2
    }
    func banana() {
        print("b banana")
    }
}
class GrandsonClass: SonClass {
    var c: Int
    init(c: Int) {
        self.c = c            // (1) ------------ 阶段1
        super.init(b: 2)
        cat()                 // (6) ------------ 阶段2
    }
    func cat() {
        print("c cat")
    }
}
let c = GrandsonClass(c: 3)

打印结果

a apple
b banana
c cat

两段式构造的优点:
(1)防止属性值在初始化之前被访问
(2)防止属性值被另一个构造器意外的赋值(??)

4个安全检查

为了保证两段式构造能顺利进行,编译器对代码进行4个安全检查

安全检查1

在调用父类的构造器前,要保证本类的属性全部赋初始值(这是初始化)。

安全检查2

必须先调用父类的构造器,然后再定制属性的值(这是定制),否则定制的属性值会被父类构造器覆盖。

安全检查3

便利构造器必须先调用同类的其他构造器,然后再定制属性的值(便利构造器定制属性值),否则定制的属性值会被同类的其他构造器覆盖。

安全检查4

在第1阶段没有完成前,不能调用实例的方法,不能读取属性值,不能引用self作为值使用。

只要理解了两段式构造,自然就知道为什么会有这4个检查了,慢慢体会!!我也是晕了很久的,哈哈。

指定构造器和便利构造器用途

指定构造器主要用于初始化属性,给属性赋值。
便利构造器主要方便外部函数调用,最后还是要调用指定构造器对属性进行初始化。

只要认清这2点,应该知道用哪种构造器。

构造器的自动继承

如果子类的属性都有默认值,或者是可选的,并且没有定义任何的构造器,这个情况下,子类就会自动继承父类所有构造器。

可失败构造函数

如果构造函数传入的参数不符合需求,则可以返回nil

class ITPerson {
    var name: String
    var sex: String
    init?(name: String, sex: String) {
        if sex != "male" {
            return nil
        }
        self.name = name
        self.sex = sex
    }
}

如果sex不是male的话,则返回nil,使用这种构造函数创建实例,这个实例的类型属于可选类型,ITPerson?

var person = ITPerson(name: "johan", sex: "female") // person类型为ITPerson?
person?.name

必要构造器

init前面加上“required”就是必要构造器了,表明该类的子类都要实现该构造器。

class Person {
    required init() {
        // 必要构造函数
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值