Swift基础 类的初始化方法-构造函数

类的初始化

类的初始化是调用init()方法进行的,在 Objective-C 中,init()方法是不安全的,因为init()方法可能被调用不止一次,也不能保证初始化后所有的成员属性都不为空、都有值。

  • 对于不需要立刻初始化的属性,需要在声明类型后增加 符号

Designated(指定的、标记的)

所以 Swift 有了超级严格的初始化方法。一方面,Swift 强化了 designated 初始化方法的地位。Swift 中不加修饰的 init 方法都需要在方法中保证所有非 Optional 的实例变量被赋值初始化,而在子类中也强制 (显式或者隐式地) 调用 super 版本的 designated 初始化,所以无论如何走何种路径,被初始化的对象总是可以完成完整的初始化的。

class Person{
    
    
    let name : String
    let height : Double
    let sex : String
    
    init(personName: String, personHeight: Double, personSex: String) {
    
    
        name = personName
        height = personHeight
        sex = personSex
    }
}

class Student: Person {
    
    
    let index : Int
    let profession : String
    
    init(person:Person,studentIndex:Int,studentProfession:String) {
    
    
        index = studentIndex
        profession = studentProfession
        super.init(personName: person.name, personHeight: person.height, personSex: person.sex);
    }
}

class ViewController: UIViewController {
    
    

    override func viewDidLoad() {
    
    
        super.viewDidLoad()
        
        let xiaoMingPerson = Person.init(personName: "xiaoMing", personHeight: 172.5, personSex: "男")
        let xiaoMingStudent = Student.init(person: xiaoMingPerson, studentIndex: 202102, studentProfession: "汉语言文学")
        
        print(xiaoMingStudent.name)
        
    }
}

运行结果:

xiaoMing

Swiftlet 声明的值是不变量,通常情况下无法赋值。

但我们可以发现在上述代码中,在 init() 方法里可以对 let 常量进行赋值,这是 init() 初始化方法的重要特点。

而因为 Swiftinit() 只可能被调用一次,因此在 init 中我们可以为 let常量 进行赋值,而不会引起任何线程安全的问题。

Convenience(方便、便利)

designated 初始化方法对应的是在 init() 前加上 convenience 关键字的初始化方法。

我们在一些特殊的场合会有一些标准化的初始化流程,所以 convenience 的好处在于作为补充和提供使用上的方便,我们可以编写除唯一指定的初始化外其他的初始化方式。

一般是在使用系统的类进行扩充,比如UIButton,想要扩充一个UIButton(imageName:String,selected:String)构造方法,可以采用Convenience关键字进行修饰。

便利构造函数中需要调用self.init()方法。

但是所有的 convenience 初始化方法都必须调用同一个类中的 designated 初始化完成设置,另外 convenience 的初始化方法是不能被子类重写的,也不能从子类中以 super 的方式被调用。

class Person{
    
    
    let name : String
    let height : Double
    let sex : String
    
    init(personName: String, personHeight: Double, personSex: String) {
    
    
        name = personName
        height = personHeight
        sex = personSex
    }
    //此处表示一些特殊的场合
    //比如我们只需要用户名,其他属性非必须
    //但始终都需要调用designated指定的初始化来实现该类有且仅被初始化一次。
    convenience init(personName: String) {
    
    
        self.init(personName: personName,personHeight: 0.0,personSex: "")
    }
}

class Student: Person {
    
    
    let index : Int
    let profession : String
    
    init(person:Person,studentIndex:Int,studentProfession:String) {
    
    
        index = studentIndex
        profession = studentProfession
        super.init(personName: person.name, personHeight: person.height, personSex: person.sex);
    }
    convenience init(person:Person,studentIndex:Int) {
    
    
        self.init(person: person,studentIndex: studentIndex,studentProfession: "")
    }
}

class ViewController: UIViewController {
    
    

    override func viewDidLoad() {
    
    
        super.viewDidLoad()
        
        let xiaoMingPerson = Person.init(personName: "xiaoMing")
        let xiaoMingStudent = Student.init(person: xiaoMingPerson, studentIndex: 202102)
        
        print(xiaoMingStudent.name)
        
    }
}

运行结果:

xiaoMing

只要在子类中实现重写了父类 convenience 方法所需要的init方法,我们在子类中就也可以使用父类的 convenience 初始化方法了。

  • 初始化路径必须保证对象完全初始化,这可以通过调用本类型的 designated 初始化方法来得到保证。
  • 子类的designated 初始化方法必须调用父类的designated 方法,以保证父类也完成初始化。

Required(子类必须重新实现)

添加 required 关键字进行限制,可以强制子类对init()方法重写实现。这样的一个最大的好处是可以保证依赖于某个 designated 初始化方法的 convenience 一直可以被使用。

class Person{
    
    
    let name : String
    let height : Double
    let sex : String
    
    
    required init(personName: String, personHeight: Double, personSex: String) {
    
    
        name = personName
        height = personHeight
        sex = personSex
    }
    
    convenience init(personName: String) {
    
    
        self.init(personName: personName,personHeight: 0.0,personSex: "")
    }
}

class Student: Person {
    
    
    var isStudent : Bool
    
    required init(personName: String, personHeight: Double, personSex: String) {
    
    
        isStudent = true
        super.init(personName: personName, personHeight: personHeight, personSex: personSex)
    }
}

class ViewController: UIViewController {
    
    

    override func viewDidLoad() {
    
    
        super.viewDidLoad()
        
        let xiaoMingStudent = Student.init(personName: "xiaoMing")
        print(xiaoMingStudent.isStudent)
        
    }
}

运行结果:

true

猜你喜欢

转载自blog.csdn.net/kkkenty/article/details/124785429