初始化 反初始化

纵饮孤独 提交于 2020-04-04 07:48:21

 

//===============================

/*

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

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

 3.类类型的实例同样可以实现一个反初始化器,它会在这个类的实例被释放之前执行任意的自定义清理

 */

 

//在创建类和结构体的实例时必须为所有的存储属性设置一个合适的初始值。存储属性不能遗留在不确定的状态中。你可以在初始化器里为存储属性设置一个初始值,或者通过分配一个默认的属性值作为属性定义的一部分

 

 

//初始化器在创建特定类型的实例时被调用。在这个简单的形式中,初始化器就像一个没有形式参数的实例方法,使用 init 关键字来写:

//init(){

//    

//}

//

 

struct Fahrenheit {

    var temperature:Double

    init() {

        temperature = 10.0

    }

}

 

let fahren = Fahrenheit()

print("value is \(fahren.temperature)")

 

//可以通过输入形式参数和可选类型来自定义初始化过程,或者在初始化的时候分配常量属性

 

//可以提供初始化形式参数作为初始化器的一部分,来定义初始化过程中的类型和值的名称。初始化形式参数与函数和方法的形式参数具有相同的功能和语法

//初始化形式参数

struct Celsius {

    

    var temperatureInCelsius:Double

    

    init(fromFahrenheit fahrenheit:Double) {

        

        temperatureInCelsius = (fahrenheit - 32.0) / 1.8

    }

    

    init(fromKelvin kelvin:Double) {

        temperatureInCelsius = kelvin - 273.15

    }

    

    

    //无实际参数标签的初始化器形式参数

    init(_ kkk:Double) {

        temperatureInCelsius = kkk + 111

    }

    

   

 

 

}

 

 

let boilingPointOfWater = Celsius.init(fromKelvin: 11)

 

let freezingPointOfWater = Celsius.init(fromFahrenheit: 12)

 

 

//形式参数名和实际参数标签

//与函数和方法的形式参数一样,初始化形式参数也可以在初始化器内部有一个局部变量名以及实际参数标签供调用的时候使用

//总之,初始化器并不能像函数和方法那样在圆括号前面有一个用来区分的函数名。因此,一个初始化器的参数名称和类型在识别该调用哪个初始化器的时候就扮演了一个非常重要的角色。因此,如果你没有提供外部名 Swift 会自动为每一个形式参数提供一个外部名称

 

struct color {

    //形式参数名和实际参数标签

    let red,green,blue:Double

    init(red:Double,green:Double,blue:Double) {

        

        self.red = red

        self.green = green

        self.blue = blue

        

    }

 

}

 

let mata = color.init(red: 2, green: 3, blue: 4)

 

 

 

//可选属性类型 加一个?实现    在初始化中分配常量属性 let

//1.如果你的自定义类型有一个逻辑上是允许无值的存储属性——大概因为它的值在初始化期间不能被设置,或者因为它在稍后允许设置为无值”——声明属性为可选类型。可选类型的属性自动地初始化为 nil ,表示该属性在初始化期间故意设为还没有值

 

//2.在初始化的任意时刻,你都可以给常量属性赋值,只要它在初始化结束是设置了确定的值即可。一旦为常量属性被赋值,它就不能再被修改了。

class SurveyQuestion{

    

    var test:String

    var respond:String? //可选属性类型

    let question:String //常量属性

 

    

    init(test:String) {

        self.test = test

        self.question = test //常量属性被赋值,它就不能再被修改了

    }

    

    

    func ask(){

        print(test)

    }

    

    

    

    

    

}

 

 

 

let cheeseQuestion = SurveyQuestion(test: "Do you like cheese?")

cheeseQuestion.ask()

cheeseQuestion.respond = "Yes"

 

//默认初始化器

class NoInit {

    

    var num:Int?

    var name = "slc"

    

}

 

//所有属性都有默认值,又由于它是一个没有父类的基类, ShoppingListItem 类自动地获得了一个默认的初始化器,使用默认值设置了它的所有属性然后创建了新的实例

let no = NoInit()

 

 

 

 

//结构体类型的成员初始化器

 

//如果结构体类型中没有定义任何自定义初始化器,它会自动获得一个成员初始化器。不同于默认初始化器,结构体会接收成员初始化器即使它的存储属性没有默认值。这个成员初始化器是一个快速初始化新结构体实例成员属性的方式。新实例的属性初始值可以通过名称传递到成员初始化器里。

 

struct Size {

    var width = 0.0 , height = 0.0

    

}

 

 

 

let size = Size(width: 2.0, height: 2.0)

let size2 = Size()

 

 

 

 

//初始化器可以调用其他初始化器来执行部分实例的初始化。这个过程,就是所谓的初始化器委托,避免了多个初始化器里冗余代码,对于值类型,当你写自己自定义的初始化器时可以使用 self.init 从相同的值类型里引用其他初始化器。你只能从初始化器里调用 self.init

struct Point {

    

    var x = 0.0,y = 0.0

}

 

 

struct Rect {

    

    var origin = Point()

    var size = Size()

    

    init() {}

 

    init(origin:Point ,size:Size) {

        

        self.origin = origin

        self.size = size

    }

    

    init(center:Point,size:Size) {

        let originX = center.x - (size.width/2.0)

        let originY = center.y - (size.height/2.0)

        

        self.init(origin:Point(x: originX,y:originY),size: size)

    }

}

 

 

 

 

/*

 类的继承和初始化

 所有类的存储属性——包括从它的父类继承的任何属性——必须在初始化期间分配一个初始值。

 Swift 为类类型定义了两种初始化器以确保所有的存储属性接收一个初始值。这些就是所谓的指定初始化器和便捷初始化器。

*/

 

//convenience init(){

//    

//}

 

 

//初始化器的继承和重写

class superClass {

    var key:String

    

    init(key keyis:String) {

        key = keyis

    }

    

}

 

class subClass: superClass {

    

    override init(key:String){

        super.init(key: key)

    }

}

 

 

 

//指定和便利初始化器的操作

class Food {

    

    var name:String?

    

    init(name:String) {

        self.name = name

    }

    

    convenience init(){

        self.init(name:"[unnamed]")

    }

    

}

 

let nameMeth = Food.init()

 

 

 

class RecipeIngredient: Food {

    var quantity:Int

    

    init(name:String,quant:Int) {

        self.quantity = quant

        super.init(name: name)

    }

    

    

    override convenience init(name:String) {

        self.init(name:name,quant:1)

    }

}

 

let oneMysteryItem = RecipeIngredient()

let oneBacon = RecipeIngredient(name: "Bacon")

let sixEggs = RecipeIngredient(name: "Eggs", quant: 6)

 

 

 

class BreakFrist: RecipeIngredient {

    var purchased = false

    

    var dis:String {

        var output = "\(quantity) x \(name)"

        output += purchased ? " " : " "

        return output

    }

}

 

 

var breakFrist = [BreakFrist(),BreakFrist.init(name: "Eggs", quant: 0),BreakFrist(name:"Bacon")]

 

 

breakFrist[0].name = ""

breakFrist[1].purchased = true

for item in breakFrist{

    print(item.dis)

}

 

//可失败初始化器  通过在 init 关键字后面添加问号( init? )来写

struct Animal{

    

    let species:String;

    

    init?(name:String) {

        

        if name.isEmpty {return nil}

        

        self.species = name;

    }

}

 

let someCreature = Animal(name: "Giraffe")

 

if let giraffe = someCreature {

     print("An animal was initialized with a species of \(giraffe.species)")

}

 

 

 

let anonymousCreature = Animal(name:"")

// anonymousCreature is of type Animal?, not Animal

 

if anonymousCreature == nil {

    print("The anonymous creature could not be initialized")

}

 

 

//枚举的可失败初始化器

enum TemperatureUnit {

    

     case Kelvin, Celsius, Fahrenheit

    init?(symbol: Character) {

        switch symbol {

        case "K":

            self = Kelvin

        case "C":

            self = Celsius

        case "F" :

            self = Fahrenheit

        default:

            return nil

        }

    }

}

 

let fahrenheitUnit = TemperatureUnit(symbol: "F")

if fahrenheitUnit != nil {

    print("This is a defined temperature unit, so initialization succeeded.")

}

 

//带有原始值枚举的可失败初始化器 带有原始值的枚举会自动获得一个可失败初始化器 init?(rawValue:) ,该可失败初始化器接收一个名为 rawValue 的合适的原始值类型形式参数如果找到了匹配的枚举情况就选择其一,或者没有找到匹配的值就触发初始化失败。

enum Temperature: Character {

    case Kelvin = "K", Celsius = "C", Fahrenheit = "F"

}

 

 

//初始化失败的传递

//类,结构体或枚举的可失败初始化器可以横向委托到同一个类,结构体或枚举里的另一个可失败初始化器。类似地,子类的可失败初始化器可以向上委托到父类的可失败初始化器。无论哪种情况,如果你委托到另一个初始化器导致了初始化失败,那么整个初始化过程也会立即失败,并且之后任何初始化代码都不会执行。

 

 

class Product {

    let name: String

    init?(name: String) {

        if name.isEmpty { return nil }

        self.name = name

    }

}

 

class CartItem: Product {

    let quantity: Int

    init?(name: String, quantity: Int) {

        if quantity < 1 { return nil }

        self.quantity = quantity

        super.init(name: name)

    }

}

 

 

if let zeroShirts = CartItem(name: "shirt", quantity: 0) {

    print("Item: \(zeroShirts.name), quantity: \(zeroShirts.quantity)")

} else {

    print("Unable to initialize zero shirts")

}

 

//如果你尝试创建一个 CartItem 实例,并且令 name 为空值,那么父类 Product 的初始化器就会导致初始化失败:

if let oneUnnamed = CartItem(name: "", quantity: 1) {

    print("Item: \(oneUnnamed.name), quantity: \(oneUnnamed.quantity)")

} else {

    print("Unable to initialize one unnamed product")

}

 

 

 

//重写可失败初始化器

//你可以在子类里重写父类的可失败初始化器。就好比其他的初始化器。或者,你可以用子类的非可失败初始化器来重写父类可失败初始化器。这样允许你定义一个初始化不会失败的子类,尽管父类的初始化允许失败。如果你用非可失败的子类初始化器重写了一个可失败初始化器,向上委托到父类初始化器的唯一办法是强制展开父类可失败初始化器的结果。

 

 

 

 

//必要初始化器

 

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

class SomeClas {

    required init() {

        // initializer implementation goes here

    }

}

//当子类重写父类的必要初始化器时,必须在子类的初始化器前同样添加 required 修饰符以确保当其它类继承该子类时,该初始化器同为必要初始化器。在重写父类的必要初始化器时,不需要添加 override 修饰符:

class SomeSubclass: SomeClas {

    required init() {

        // subclass implementation of the required initializer goes here

    }

}

 

 

 

//通过闭包和函数来设置属性的默认值

//如果某个存储属性的默认值需要自定义或设置,你可以使用闭包或全局函数来为属性提供默认值。当这个属性属于的实例初始化时,闭包或函数就会被调用,并且它的返回值就会作为属性的默认值。这种闭包或函数通常会创建一个和属性相同的临时值,处理这个值以表示初始的状态,并且把这个临时值返回作为属性的默认值。

 

 

class SomeClass {

    let someProperty: String = {

        // create a default value for someProperty inside this closure

        // someValue must be of the same type as SomeType

        return "ssss"

    }()

}

 

 

struct Chessboard {

    let boardColors: [Bool] = {

        var temporaryBoard = [Bool]()

        var isBlack = false

        for i in 1...8 {

            for j in 1...8 {

                temporaryBoard.append(isBlack)

                isBlack = !isBlack

            }

            isBlack = !isBlack

        }

        return temporaryBoard

    }()

    func squareIsBlackAt(row: Int, column: Int) -> Bool {

        return boardColors[(row * 8) + column]

    }

}

 

//无论何时,创建一个新的 Checkboard ,闭包就会执行,并且 boardColors 的默认值就会计算和返回

 

let board = Chessboard()

print(board.squareIsBlackAt(row: 0, column: 1))

// Prints "true"

print(board.squareIsBlackAt(row: 7, column: 7))

 

 

 

 

//反初始化

//在类实例被释放的时候,反初始化器就会立即被调用。你可以是用 deinit 关键字来写反初始化器,就如同写初始化器要用 init 关键字一样。饭初始化器只在类类型中有效 每个类当中只能有一个反初始化器。反初始化器不接收任何形式参数,并且不需要写圆括号反初始化器会在实例被释放之前自动被调用。你不能自行调用反初始化器。父类的反初始化器可以被自雷继承,并且子类的反初始化器实现结束之后父类的反初始化器会被调用。父类的反初始化器总会被调用,就算子类没有反初始化器。由于实例在反初始化器被调用之前都不会被释放,反初始化器可以访问实例中的所有属性并且可以基于这些属性修改自身行为(比如说查找需要被关闭的那个文件的文件名)

class Bank {

    

    static var coinsInBank = 10

    

    static func distribute(coins numberOfCoinsRequested:Int) -> Int {

        let numberOfCoinsToVend = min(numberOfCoinsRequested, coinsInBank)

        

        coinsInBank -= numberOfCoinsToVend

        

        return numberOfCoinsToVend;

    }

    

    static func receive(coins:Int){

        coinsInBank += coins

    }

    

    

}

 

 

class Player {

    var coinesInPurse:Int

    init(coins:Int) {

        coinesInPurse = Bank.distribute(coins: coins)

    }

    

    func win(coins:Int) {

         coinesInPurse += Bank.distribute(coins: coins)

    }

    

    deinit {

        Bank.receive(coins: coinesInPurse)

    }

    

}

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!