swift

Swift基础9(初始化)

2020-02-03  本文已影响0人  SunshineBrother

初始化

初始化是为类、结构体或者枚举准备实例的过程。这个过需要给实例里的每一个存储属性设置一个初始值并且在新实例可以使用之前执行任何其他所必须的配置或初始化

你通过定义初始化器来实现这个初始化过程,它更像是一个用来创建特定类型新实例的特殊的方法。不同于 Objective-C 的初始化器,Swift 初始化器不返回值。这些初始化器主要的角色就是确保在第一次使用之前某类型的新实例能够正确初始化。

类有两种初始化器

class Person {
    var age: Int
    var name: String
    
    //指定初始化器
    init(age:Int, name:String) {
        self.age = age
        self.name = name
    }
    //便捷初始化器
    convenience init(age:Int){
        self.init(age:age,name:"")
    }
}

初始化器的相互调用规则

使用这一套规则保证了使用任意初始化器都可以完成的初始化实例

指定初始化器必须从他的直系父类调用指定初始化器

class Person {
    var age = 0
    init(age:Int) {
        self.age = age
    }
}

class Student: Person {
    var score = 0
    init(age:Int,score:Int) {
        self.score = score
        super.init(age: age)
    }
}

便捷初始化器必须从相同的类里调用另一个初始化器

class Size {
    var height = 0
    var width = 0
    
    init(height:Int,width:Int) {
        self.height = height
        self.width = width
    }
    
    convenience init(width:Int){
        self.width = width
    }
}

上面的错误日志就是,在convenience需要先初始化

convenience init(width:Int){
        self.init(height:0, width:width)
        self.width = width
    }

其实这种是一种比较安全的设计,我们在指定初始化器中初始化好所有必须要初始化的值,在便捷初始化中,调用指定初始化器,这样就不会出现一些忘记初始化的值

两段式初始化

swift在编码安全方面,为了保证安全,设定了两段式安全检查

两段式初始化第一阶段

第一阶段初始化所有的存储属性

class Person {
    var age:Int
    init(age:Int) {
        self.age = age
    }
}
class Student: Person {
    var score:Int!
    init(age:Int,score:Int) {
        self.score = score  //3、指定初始化器确保当前类定义的存储属性都初始化
        super.init(age: age)
    }
}
//1、外层调用指定\便捷初始化器
var stu = Student(age: 10, score: 99)

1、外层调用指定\便捷初始化器
这句话就是var stu = Student(age: 10, score: 99)这句代码

2、分配内存给实例,但并未初始化

这个时候我们需要查看汇编了
var stu = Student(age: 10, score: 99)打断点查看汇编,汇编代码如下

 0x100000bfe <+46>: callq  0x1000011f0  ; 
初始化.Student.__allocating_init(age: Swift.Int, score: Swift.Int) -> 
初始化.Student at main.swift:35

3、指定初始化器确保当前类定义的存储属性都初始化

对于Student就是这句赋值代码self.score = score

4、指定初始化器调用父类的初始化器,不断向上,形成初始化器链

子类Student调用父类Person的初始化器init(age:Int) {}

两段式初始化第二阶段

第二阶段设置新的存储属性

class Student: Person {
    var score:Int
    init(age:Int,score:Int) {
        self.test()
        self.score = score
        super.init(age: age)
    }
    
    func test() {
    }
    
}

他会在self.test()处报错'self' used in method call 'test' before 'super.init' call是因为两段式初始化第一阶段的3、指定初始化器确保当前类定义的存储属性都初始化还没有完成,当把self.test() 放到super.init(age: age) 就可以了。

安全检查

重写

class Person {
    var age:Int
    init(age:Int) {
        self.age = age
    }
}

class Student: Person {
    var score:Int
    init(age:Int,score:Int) {
        self.score = score
        super.init(age: age)
    }
    
    override init(age: Int) {
        super.init(age: age)
    }
}

这时在super.init(age: age)报错Property 'self.score' not initialized at super.init call,是因为自己的存储属性还没有初始化结束

override init(age: Int) {
        self.score = 10
        super.init(age: age)
    }

这样写就不报错了。

如果子类写了一个匹配父类便捷初始化器的初始化器,不用加上override

class Person {
    var age:Int
    var name:String
    init(age:Int,name:String) {
        self.age = age
        self.name = name
    }
    
    convenience init(age:Int){
        self.init(age:age,name:"")
        self.age = age
    }
    
    
}

class Student: Person {
    var score:Int
    init(age:Int,score:Int) {
        self.score = score
        super.init(age: age,name:"")
    }
    
    init(age:Int) {
        self.score = 99
        super.init(age: age, name: "")
    }
    
}
var stu = Student(age: 10)
 

我们在Person的便捷初始化器 convenience init(age:Int){}和子类Student的指定初始化器init(age:Int) {}打断点,我们可以发现并没有走到Person的便捷初始化器 convenience init(age:Int){}里面

便捷初始化器只能横向调用,不能够继承,被重写

自动继承

required

class Person {
    required init() {
        
    }
 
}
class Student: Person {
    required init() {
        super.init()
    }
}

属性观察器

父类的属性在他自己的初始化器中赋值不会触发属性观察器,但在子类的初始化器中赋值会触发属性观察器

class Person {
    var age:Int{
        willSet{
            print("willSet",newValue)
        }
        didSet{
            print("didSet","oldValue:\(oldValue)","age:\(age)")
        }
    }
    
    init() {
        self.age = 0
    }
 
}
class Student: Person {
    override init() {
        super.init()
        self.age = 1
    }
}

var stu = Student()

打印
willSet 1
didSet oldValue:0 age:1

反初始化器deinit

deinit叫做反初始化器,类似OC中的dealloc

当类中的实例对象被释放内存的时,就会调用实例对象的deinit

class Student: Person {
    override init() {
        super.init()
        self.age = 1
    }
    
    deinit {
        print("Student对象销毁")
    }
}

上一篇下一篇

猜你喜欢

热点阅读