swift5.x 类初始化反初始化, 指定初始化器,便利初始化器

Posted wjw-blog

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了swift5.x 类初始化反初始化, 指定初始化器,便利初始化器相关的知识,希望对你有一定的参考价值。

//
//  ViewController8.swift
//  swiftT
//
//  Created by wjwdive on 2020/5/22.
//  Copyright ? 2020 wjwdive. All rights reserved.
//

import UIKit

class ViewController8: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let f = Fahrenheit()
        print("the default temperature is (f.temperature)")
     
        let item = ShoppingListItem()

        //自定义初始化器
        let bollingPointWater = Celsius(fromFahrenheit: 212.0)
        let freezingPointWater = Celsius(fromKelvin: 273.15)
        
        //在初始化的时候分配常量属性
        let beetsQuestion = SurveyQuestion(text: "How about beets?")
        beetsQuestion.ask()
        beetsQuestion.response = "I also like beets, (But not with cheese.)"
     
        
        //结构体成员初始化器
        let siezee = Sizee(width: 1.0, height: 2.0)
        
        
    }
}


//类的初始化和反初始化
// 初始化器在创建类型的实例时被调用
struct Fahrenheit {
    var temperature: Double
    init() {
        temperature = 32.0
    }
}//华氏度

// Swift 为所有没有提供初始化器的结构体或类提供了一个默认的初始化器来给所有的属性提供了默认值。这个默认的初始化器只是简单地创建了一个所有属性都有默认值的新实例

class ShoppingListItem {
    var name: String?
    var quantity = 1
    var purchased = false
}

// 自定义初始化
// 可以提供初始化形式参数作为初始化器的一部分,来定义初始化过程中的类型和值的名称。初始化形式参数与函数和方法的形式参数具有相同的功能和语法
struct Celsius {
    var temperatureInCelsius: Double
    init(fromFahrenheit fahrenheit: Double) {
        temperatureInCelsius = (fahrenheit - 32.0)/1.8
    }
    init(fromKelvin kelvin: Double) {
        temperatureInCelsius = kelvin - 273.15
    }
}//摄氏度

// 在初始化中分配常量属性
// 在初始化的任意时刻,你都可以给常量属性赋值,只要它在初始化结束时设置了确定的值即可。一旦为常量赋值,它就不能修改了
class SurveyQuestion {
    let text: String
    var response: String?
    init(text: String) {
        self.text = text
    }
    func ask() {
        print(text)
    }
}


// 结构体的成员初始化器
// 如果结构体类型中没有定义任何自定义初始化器,它会自动获得一个成员初始化器。不同于默认初始化,结构体会接收成员初始化器即使他的存储属性没有默认值
struct Sizee {
    var width = 0.0, height = 0.0
}


//值类型的初始化器委托
// 初始化器可以调用其他初始化器来执行部分实例的初始化。这个过程,就是所谓的初始化器委托,避免了多个初始化器里冗余代码
struct Sizet{
    var width = 0.0, height = 0.0
}
struct Pointt {
    var x = 0.0, y = 0.0
}

struct Rectt {
    var origin = Pointt()
    var size = Sizet()
    init() {}//1
    init(origin: Pointt, size: Sizet) {
        self.origin = origin
        self.size = size
    }//2
    // 运用了初始化器2
    init(center: Pointt, size: Sizet) {
        let originX = center.x - size.width/2
        let originY = center.y - size.height/2
        self.init(origin: Pointt(x: originX, y: originY), size: size)
    }//3
    
}


//类的继承和初始化
// 1、所有类的存储属性(包括从它的父类继承的所有属性)都必须在初始化期间分配初始值
// 2、Swift为类类型定义了两种初始化器以确保所有的存储属性接收一个初始值,这些就是所谓的制定初始化器和便捷初始化器
// 3、制定初始化器时类的主要初始化器。制定的初始化器可以初始化所有那个类引用的属性并且调用合适的父类初始化器来继续这个初始化过程给父类链。
// 4、类偏向于少量指定初始化器,并且一个类通常只有一个指定初始化器,指定初始化器时初始化开始并持续初始化过程到父类链的传送点
// 5、每个类至少应该有一个指定初始化器。如同在初始化器的自动继承里描述的那样,在某些情况下,这些需要通过从父类继承一个或多个指定初始化器来满足
// 6、便捷初始化器时次要的。你可以在同一个类里定义一个便捷初始化器来调用一个指定的初始化器作为便捷初始化器来给指定初始化器设置默认形式参数。你也可以为具体的使用情况或输入的值类型定义一个便捷初始化器从而创建这个实例
// 7、如果你的类不需要便捷初始化器你可以不提供它。在为通用的初始化模式超级快捷方式可以结神时间或者类的初始化更加清晰明了的时候使用便捷初始化器。

// 指定初始化器。与值类型的简单初始化器相同的方式来写的制定初始化器
/*
init(parameters params) {
    statements
}
*/

//便捷初始化器 用convenience  修饰符放到init关键字前定义 便捷初始化器
/*
convenience init(parameters params) {
    statements
}
*/

// 类的初始化委托
// 指定初始化器必须从它的直系父类调用指定初始化器
// 便捷初始化器必须从相同的类里调用另一个初始化器
// 便捷初始化器最终必须调用一个指定初始化器

// 两段式初始化
// 1、Swift的类初始化是一个两段式过程。 在第一个阶段,每一个存储属性被引入类分配了一个初始值。一旦每个属性的初始化状态被确定。第二个阶段就开始了,每个类都有机会在新的实例准备使用之前定制他的存储属性
// 2、两段初始化过程的使用让初始化更加安全,同时在每个类的层级结构给与了完备的灵活性。两段式初始化过程可以防止属性值在初始化之前被访问,还可以防止属性值被另一个初始化器意外地赋予不同的值

// 两段式初始化过程
// 1、指定初始化器必须保证在向上委托给父类初始化器之前,其所在类引入的所有属性都要初始化完成
// 2、指定初始化器必须向上委托父类初始化器,然后才能为继承的属性设置新值。如果不这样做,指定初始化器赋予的新值将被父类中的初始化器所覆盖
// 3、便捷初始化器必须先委托同类中的其他初始化器,然后再为任意属性赋新值(包括同类里定义的属性)。如果没这么做,便捷初始化器赋予的的新值将被自己类中其他指定初始化器所覆盖
// 4、初始化器在第一阶段初始化完成之前,不能调用任何实例方法、不能读取任何实例属性的值,也不能引用self作为值


class PersonInit {
    var name: String
    var age: Int
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
    convenience init(){
        self.init(name: "[Unname]", age: 0)
    }
}

class TeacherA: PersonInit {
    var salary: Int
    init(name: String, age: Int, salary: Int) {
        //子类的属性必须在 父类初始化器调用之前初始化,否则安全检查报错
        self.salary = 0
        
        super.init(name: name, age: age)
        //子类的属性必须在 父类初始化器调用之前初始化,否则安全检查报错
        //self.salary = 0 // 位置错误
        self.name = name
        self.age  = age
    }
    
    convenience init(name: String) {
        self.init(name: name, age: 30, salary:5000)
    }
    
    func showInfo() {
        print("teacher name (name), age (age), salary (salary)")
    }
}

class TeacherB: PersonInit {
    var salary: Int
    init(name: String, age: Int, salary: Int) {
        self.salary = 0
        
        //指定初始化器必须向上委托父类初始化器,然后才能为继承的属性设置新值。
        // self.name = name + "老师" // 位置错误

        super.init(name: name, age: age)
        self.age  = age
    }
    
    convenience init(name: String) {
        self.init(name: name, age: 30, salary:5000)
    }
    
    func showInfo() {
        print("teacher name (name), age (age), salary (salary)")
    }
}


class TeacherC: PersonInit {
    var salary: Int
    init(name: String, age: Int, salary: Int) {
        self.salary = 0
        super.init(name: name, age: age)
        self.name = name
        self.age  = age
    }
    
    convenience init(name: String) {
        //便捷初始化器必须先委托同类中的其他初始化器,然后再为任意属性赋新值
//        self.name = name + "老师"
        self.init(name: name, age: 30, salary:5000)
    }
    
    func showInfo() {
        print("teacher name (name), age (age), salary (salary)")
    }
}

class TeacherD: PersonInit {
    var salary: Int
    init(name: String, age: Int, salary: Int) {
        self.salary = 0
        //位置错误
        //4、初始化器在第一阶段初始化完成之前,不能调用任何实例方法、不能读取任何实例属性的值,也不能引用self作为值
        //self.test()
        super.init(name: name, age: age)
        self.name = name
        self.age  = age
    }
    
    convenience init(name: String) {
        //便捷初始化器必须先委托同类中的其他初始化器,然后再为任意属性赋新值
//        self.name = name + "老师"
        self.init(name: name, age: 30, salary:5000)
    }
    
    func showInfo() {
        print("teacher name (name), age (age), salary (salary)")
    }
    func test() {
        print("name ", name)
    }
}


//两段式初始化过程--阶段1
// 1、指定或便捷初始化器在类中被调用
// 2、为这个类的新实例分配内存。内存还没有被初始化
// 3、这个类的指定初始化器确保所有由类引入的存储属性都有一个值。现在这些存储属性的内存被初始化了
// 4、指定初始化器上交父类的初始化器为其存储属性执行相同的任务
// 5、这个调用父类初始化器的过程将沿着初始化链已知向上进行,直到到达初始化器链的最顶部
// 6、一旦到达了初始化器链的最顶部,在链顶部的类确保所有的存储属性都有一个值,此实例的内存被认为完全初始化了,此时第一阶段完成

//两段式初始化过程--阶段2
// 1、从顶部初始化往下,链中的每一个指定初始化器都有机会进一步定制实例。初始化器现在能够访问self并可以修改它的属性值,调用它的实例方法等等
// 2、最终,链中任何便捷初始化器都有机会定制实例以及使用self


//初始化器的继承和重写
// 1、不像在Objective-C 中的子类,Swift的子类不会默认继承父类的初始化器。Swift的这种机制防止父类的简单初始化器被一个更专用的子类继承并被用来参加一个没有完全或错误初始化的新实例的情况发生。只有在特定情况下才会继承父类的初始化器
// 2、如果你想自定义子类来实现一个或多个和父类相同的初始化器,你可以子啊子类中为哪些初始化器通过定制的实现
// 3、当你写的子类初始化器匹配父类指定初始化器的时候,你实际上可以重写那么个初始化器。因此在子类的初始化器定义之前你必须写override修饰符。如同默认初始化器所描述的那样,即使是自动提供的默认初始化器你也可以重新

//初始化器的自动继承
// 1、如果你的子类没有定义任何指定初始化器,它会继承父类的所有指定初始化器
// 2、如果你的子类提供了所有父类指定初始化器的实现-- 要么是通过规则1继承来的,要么通过在定义中提供自定义实现-- 那么它自动继承所有的父类便捷初始化器。

//可失败的初始化器
// 1、定义类、结构体、枚举 初始化时可以失败,在某些情况下会管大用。这个失败可能由以下几种方式触发,包括给初始化传入无效的形式参数值,或缺少某种外部所需的资源,又或是其他阻止初始化的情况
// 2、为了妥善处理这种可能失败的情况,在类结构体或枚举中定义一个或多个可失败的初始化器。通过在init关键字后面加问号(?)来写。

//必要初始化器
// 1、在类的初始化器前面添加required 修饰符来表明所有该类的子类都必须实现该初始化器

// 反初始化
// 1、在类实例被释放的时候,反初始化器就会立即被调用。你可以使用deinit 关键字来写反初始化器,就如同在写初始化器要用init 关键字一样。反初始化器只在类类型中有效
// 2、反初始化器会在实例被释放之前被自动调用。你不能自行调用反初始化器,父类的反初始化器可以被子类继承,并且子类的反初始化器实现结束之后父类的反初始化器实现结束之后父类的反初始化器会被调用。父类的反初始化器总会被调用,就是子类没有反初始化器。


以上是关于swift5.x 类初始化反初始化, 指定初始化器,便利初始化器的主要内容,如果未能解决你的问题,请参考以下文章

为啥结构在 Swift 中没有像类一样的反初始化器?

什么时候一个类会有多个指定的初始化器?

为啥类内初始化器只能使用 = 或 ? [复制]

为啥类内初始化器只能使用 = 或 ? [复制]

CoreData:错误:无法在 NSManagedObject 类“视频”上调用指定的初始化程序

如何根据json中的属性编写jackson反序列化器