寒城攻略:Listo 教你 25 天学会 Swift 语言 - 16 Initialization

import Foundation


//***********************************************************************************************

//1.Initialization(构造过程)

//_______________________________________________________________________________________________

//介绍

//构造过程是为了使用某个类,结构体或者枚举类型的实例而进行的准备过程。这个过程包含了为实例中的每个属性设置初始值和为其执行必要的准备和初始化任务

//构造过程通过定义构造器(Initializers)来实现,这些构造器可以看做是用来创建特定类型的特殊方法


//***********************************************************************************************

//2.Setting Initial Values for Stored Properties(存储型属性的初始值)

//_______________________________________________________________________________________________

//介绍

//类和结构体在实例创建时,必须为所有的存储型属性设置合适的初始值,因为存储型属性不能处于一个未知的状态

//我们可以在构造器中为存储型属性赋初值,也可以在定义属性时为其设置默认值

//注意:当我们为存储型属性设置默认值或者在构造器中为其赋值时,它们的值是被直接设置的,不会触发任何属性观测器


//_______________________________________________________________________________________________

//构造器的实例代码

struct Fahrenheit{

    var temperature: Double

    init(){

        temperature = 32.0

    }

}

var f = Fahrenheit()

println("The default remperaturle is \(f.temperature)")


//_______________________________________________________________________________________________

//默认属性值

//我们上面是在构造器中存储属性设置的初始值,我们也可以在声明属性的时候设置默认值

struct Fahrenheit1{

    var temperture = 32.0

}

let fahrenheit1 = Fahrenheit()

println(fahrenheit1.temperature)


//***********************************************************************************************

//3.Customizing Initialization(定制化构造过程)

//_______________________________________________________________________________________________

//介绍

//我们可以通过输入参数和可选属性类型定制构造过程,也可以在构造过程中修改常量属性


//_______________________________________________________________________________________________

//构造参数:你可以在定义构造器时提供构造参数,为其提供定制化构造所需值的类型和名字。构造器参数的功能和语法跟函数和方法参数相同

//实例代码演示

struct Celsius{

    var temperatureInCelsius: Double = 0.0

    init(fromFahrenheit fahrenheit: Double){

        temperatureInCelsius = (fahrenheit - 32.0) / 1.8

    }

    init(fromKelvin kelvin: Double){

        temperatureInCelsius = kelvin - 273.15

    }

}

let boilingPointOfWater = Celsius(fromFahrenheit: 212.0)

let freezingPointOfWater = Celsius(fromKelvin: 273.15)

println("the temp of boil water is \(boilingPointOfWater.temperatureInCelsius)")

println("the temp of freeze water is \(freezingPointOfWater.temperatureInCelsius)")


//_______________________________________________________________________________________________

//代码演示内部参数名和外部参数名

//构造器中的参数名自动会被定义为外部参数名,我们在需要用时直接使用即可

struct Color{

    let red = 0.0, green = 0.0, blue = 0.0

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

        self.red = red          //使用 self. 来表示默认的属性,等号右边的时参数

        self.green = green

        self.blue = blue

    }

}

let magenta = Color(red: 1.0, green: 0.0, blue: 1.0)        //在函数初始化的时候,构造器中的参数默认为外部参数,可以直接使用


//_______________________________________________________________________________________________

//可选属性类型(如果你定制的类型包含一个逻辑上允许取值为空的存储型属性--不管是因为它无法在初始 化时赋值,还是因为它可以在之后某个时间点可以赋值为空--你都需要将它定义为可选类型 optional type

class SurveyQuestion{

    var text: String                 //调查问题提出后,我们才可以回答问题

    var response: String?            //定义 response 为可选类型,表示暂时不存在这个字符串

    init(text: String){

        self.text = text

    }

    func ask(){

        println(text)

    }

}

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

println(cheeseQuestion.ask())

cheeseQuestion.response = "sure,I do like cheese"

println(cheeseQuestion.response)


//_______________________________________________________________________________________________

//代码演示构造过程中常量属性的修改

//只要在构造过程结束前常量的值能确定,你可以在构造过程中的任意时间点修改常量属性的值

class SurveyQuestion1{

    let text: String

    var response: String?

    init (text: String){

        self.text = text        //尽管 text 的数据类型为常量,我们依旧可以在构造器中修改

    }

    func ask(){

        println(text)

    }

}

let beetsQuestion = SurveyQuestion1(text: "How about beets")

println(beetsQuestion.ask())

beetsQuestion.response = "I don't like beets"

println(beetsQuestion.response)


//***********************************************************************************************

//4.Default Initializers(默认构造器)

//_______________________________________________________________________________________________

//介绍

//Swift 将为所有属性已提供默认值的且自身没有定义任何构造器的结构体或基类,提供一个默认的构造器。这个默认构造器将简单的创建一个所有属性值都设置为默认值的实例


//_______________________________________________________________________________________________

//代码演示默认构造器

class ShoppingListItem{     //由于 ShoppingListItem 类中所有的属性都有默认值,并且没有父类,所以它将自动获得默认的构造器

    var name: String?

    var quantity = 1

    var purchased = false

}

var item = ShoppingListItem()       //在创建类实例的时候,因为所有参数均有默认值,所以不需要生命参数,它有默认构造器


//_______________________________________________________________________________________________

//结构体的逐一成员构造器(除上面提到的默认构造器,如果结构体对所有存储型属性提供了默认值且自身没有提供定制的构造器,它们能自动获得一个逐一成员构造器)

struct Size{

    var width = 0.0, height = 0.0

}

let twoByTwo = Size(width: 2.0, height: 2.0)        //结构体 Size 自动获得了一个逐一成员构造器 init(width:height:)


//***********************************************************************************************

//5.Initializer Delegation for Value Types(值类型的构造器代理)

//_______________________________________________________________________________________________

//介绍

//构造器可以通过调用其它构造器来完成实例的部分构造过程。这一过程称为构造器代理,它能减少多个构造器间的代码重复

//构造器代理的实现规则和形式在值类型和类类型中有所不同。值类型(结构体和枚举类型)不支持继承,所以构造器代理的过程相对简单,因为它们只能代理任务给本身提供的其它构造器。类则不同,它可以继承自其它类(请参考继承),这意味着类有责任保证其所有继承的存储型属性在构造时也能正确的初始化。这些责任将在后续章节类的继承和构造过程中介绍

//对于值类型,你可以使用 self.init 在自定义的构造器中引用其它的属于相同值类型的构造器。并且你只能在构造器内部调用 self.init


//_______________________________________________________________________________________________

//代码演示构造器代理

struct Size1{

    var width = 0.0, height = 0.0

}

struct Point1{

    var x = 0.0, y = 0.0

}

struct Rect{

    var origin = Point1()

    var size = Size1()

    

    init(){}            //调用这个构造器将返回一个 Rect 实例,它的 origin size 属性都使用定义时的默认值 Point(x: 0.0, y: 0.0) Size(width: 0.0, height: 0.0)

    

    init(origin: Point1, size: Size1){      //这个构造器只是简单的将 origin size 的参数值赋给对应的存储型属性

        self.origin = origin

        self.size = size

    }

    

    init(center: Point1, size: Size1){          //它先通过 center size 的值计算出 origin 的坐标。然后再调用(或代理给)init(origin:size:)构造器来将新的 origin size 赋值到对应的属性中

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

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

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

    }

}

let basicRect = Rect()

println("(\(basicRect.origin.x),\(basicRect.origin.y))")


let originRect = Rect(origin: Point1(x: 2.0, y: 2.0),size: Size1(width: 5.0, height: 5.0))

println("(\(originRect.origin.x),\(originRect.origin.y))")


let centerRect = Rect(center: Point1(x: 4.0, y: 4.0),size: Size1(width: 3.0, height: 3.0))

println("(\(centerRect.origin.x),\(centerRect.origin.y))")


//***********************************************************************************************

//6.Class Inheritance and Initialization(类的继承和构造过程)

//_______________________________________________________________________________________________

//介绍

//类里面的所有存储型属性--包括所有继承自父类的属性,都必须在构造过程中设置初始值,Swift 提供了两种类型的类构造器来确保所有类实例中存储型属性都能获得初始值,它们分别是指定构造器和便利构造器


//_______________________________________________________________________________________________

//指定构造器和便利构造器

//指定构造器是类中最主要的构造器。一个指定构造器将初始化类中提供的所有属性,并根据父类链往上调用父类的构造器来实现父类的初始化

//便利构造器是类中比较次要的、辅助型的构造器。你可以定义便利构造器来调用同一个类中的指定构造器,并为其参数提供默认值。你也可以定义便利构造器来创建一个特殊用途或特定输入的实例


//_______________________________________________________________________________________________

//构造器链

/*为了简化指定构造器和便利构造器之间的调用关系,Swift 采用以下三条规则来限制构造器之间的代理调用:

    1.指定构造器必须调用其直接父类的的指定构造器

    2.便利构造器必须调用同一类中定义的其它构造器

    3.便利构造器必须最终以调用一个指定构造器结束


也就是说:

    指定构造器必须总是向上代理

    便利构造器必须总是横向代理

*/


//_______________________________________________________________________________________________

//两段式构造过程

//Swift 中类的构造过程包含两个阶段。第一个阶段,每个存储型属性通过引入它们的类的 构造器来设置初始值。当每一个存储型属性值被确定后,第二阶段开始,它给每个类一次机会在新实例准备使用之前进一步定制它们的存储型属性


//在进行两段式的时候进行4重安全检查

/*

    1.指定构造器必须保证它所在类引入的所有属性都必须先初始化完成,之后才能将其它构造任务向上代理给父类中的构造器

    2.指定构造器必须先向上代理调用父类构造器,然后再为继承的属性设置新值。如果没这么做,指定构造器赋予的新值将被父类中的构造器所覆盖

    3.便利构造器必须先代理调用同一类中的其它构造器,然后再为任意属性赋新值。如果没这 么做,便利构造器赋予的新值将被同一类中其它指定构造器所覆盖

    4.构造器在第一阶段构造完成之前,不能调用任何实例方法、不能读取任何实例属性的值, 也不能引用 self 的值

*/


//两段式在进行构造过程中的运行

/*

阶段 1

某个指定构造器或便利构造器被调用; 完成新实例内存的分配,但此时内存还没有被初始化;

指定构造器确保其所在类引入的所有存储型属性都已赋初值。存储型属性所属的内存完成初始化;

指定构造器将调用父类的构造器,完成父类属性的初始化;

这个调用父类构造器的过程沿着构造器链一直往上执行,直到到达构造器链的最顶部;

当到达了构造器链最顶部,且已确保所有实例包含的存储型属性都已经赋值,这个实例的 内存被认为已经完全初始化。此时阶段 1 完成


阶段 2

从顶部构造器链一直往下,每个构造器链中类的指定构造器都有机会进一步定制实例。构造器此时可以访问 self、修改它的属性并调用实例方法等等。 最终,任意构造器链中的便利构造器可以有机会定制实例和使用 self

*/


//_______________________________________________________________________________________________

//构造器的继承和重载

// Objective-C 中的子类不同,Swift 中的子类不会默认继承父类的构造器,假如你希望自定义的子类中能实现一个或多个跟父类相同的构造器--也许是为了完成一些定制的构造过程--你可以在你定制的子类中提供和重载与父类相同的构造器


//_______________________________________________________________________________________________

//自动构造器的继承

//子类不会默认继承父类的构造器。但是如果特定条件可以满足,父类构造器是可以被自动继承的

/*

假设要为子类中引入的任意新属性提供默认值,请遵守以下 2 个规则

    规则 1

        如果子类没有定义任何指定构造器,它将自动继承所有父类的指定构造器。

    规则 2

        如果子类提供了所有父类指定构造器的实现--不管是通过规则 1 继承过来的,还是通过自 定义实现的--它将自动继承所有父类的便利构造器

*/


//_______________________________________________________________________________________________

//指定构造器和便利构造器的语法

/*

init(/*parameters*/){       //指定构造器的写法

    //statements

}


convenience init(/*parameters*/){       //便利构造器的写法

    //statements

}

*/


//_______________________________________________________________________________________________

//指定构造器和便利构造器实战

class Food{                 //创建类层次的父类 Food

    var name: String

    init(name: String){     //定义 init(name: String) 为指定构造器,它能够确保 Food 类中所有的属性被初始化

        self.name = name

    }

        

    convenience init(){     //定义没有参数的便利构造器 init(),并且通过代理调用同一类中定义的指定构造器 init(name: String) 并给参数 name 传值[Unnamed]来实现

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

    }

}

let namedMeat = Food(name: "Banco")     //此时创建 Food 实例



class RecipeIngredient: Food{       //定义 Food 的子类 RecipeIngredient

    var quantity: Int               //它引入了 Int 类型的数量属性 quantity(以及从 Food 继承过来的 name ),并且定义了两个构造器来创建 RecipeIngredient 实例

        init(name: String, quantity: Int){      //指定构造器 init(name: String, quantity: Int),它可以用来产生新 RecipeIngredient 实例的所有属性值

        self.quantity = quantity            //这个构造器一开始先将传入的 quantity 参数赋值 quantity 属性,这个属性也是唯一在 RecipeIngredient 中新引入的属性。随后,构造器将任务向上代理给父类 Food init(name: String)

        super.init(name: name)

    }

        

    convenience init(name: String) {

    self.init(name: name, quantity: 1)      //RecipeIngredient 也定义了一个便利构造器 init(name: String),它只通过 name 来创建 RecipeIngredient 的实例。这个便利构造器假设任意 RecipeIngredient 实例的 quantity 1,所以不需要显示指明数量即可创建出实例

    }

}

let oneMysteryItem = RecipeIngredient()             //此时创建 RecipeIngredient 实例有三种方法,第一种继承自 Food

let oneBacon = RecipeIngredient(name: "Bancon")     //第二种使用 便利构造器

let sixEggs = RecipeIngredient(name: "Eggs", quantity: 6)       //第三种使用 结构构造器



class ShoppingListItem1: RecipeIngredient{       //定义 RecipeIngredient 的子类 ShoppingList

    var purchased = false       //ShoppingListItem 引入了一个布尔类型的属性 purchased,它的默认值是 false

        var description: String{        //ShoppingListItem 还添加了一个计算型属性 description,它提供了关于 ShoppingListItem实例的一些文字描述

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

        output += purchased ? " ?" : " ?"

        return output

    }           //由于它为自己引入的所有属性都提供了默认值,并且自己没有定义任何构造器,ShoppingListItem 将自动继承所有父类中的指定构造器和便利构造器

}               //ShoppingListItem 没有定义构造器来为 purchased 提供初始化值,这是因为任何添加到购物单的项的初始状态总是未购买

var breakfastList1 = [ShoppingListItem1(),ShoppingListItem1(name: "Bacon"), ShoppingListItem1(name: "Eggs", quantity: 6),

]           //使用三种方法来实例化 ShoppingListItem

breakfastList1[0].name = "Orange juice"

breakfastList1[0].purchased = true

for item in breakfastList1{

        println(item.description)

}


//***********************************************************************************************

//7.Setting a Default Property Value with a Closure or Function(通过闭包和函数来设置属性的默认值)

//_______________________________________________________________________________________________

//介绍

//如果某个存储型属性的默认值需要特别的定制或准备,你就可以使用闭包或全局函数来为其属性提供定制的默认值。每当某个属性所属的新类型实例创建时,对应的闭包或函数会被调用,而它们的返回值会当做默认值赋值给这个属性


//_______________________________________________________________________________________________

//代码实例演示通过闭包设置属性的默认值

class SomeClass{

    let someProperty: Int = {

        let number = 1

        return number

    }()             //加上 () 说明这是一个闭包,这个闭包返回一个 Int 类型的数

}

var someClass = SomeClass()

println(someClass.someProperty)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值