iOS Swift No.14 - 构造 1

第十四章 构造

构造是一个为类,结构体或和枚举的实例作准备使用的一个过程。有了类,结构体或者枚举实例的构造过程之后呢,才能更好的使他们实例的存储属性更好的设置初始值。也就是说我们要想使用某个类型的一个新的实例就必须先要对他们的存储属性构造一个初始值。这就是构造的由来以及作用。

实现这个构造的过程(Initialization Process),要先定义一个构造器(Initializer),构造器就像一个特殊的方法(方法参考章节11)可以用来调用类型(structure, class and enumeration)中的实例。swift语言里面的initializer从来不会返回某个值。initializer使用是最基本的一个规则就是,他要确保类型中的实例要被正确的初始化好,这样才能在第一次调用实例的时候不会出错。

与构造(Initialization)相反的就是析构(Deinitialization)。析构同样在实现的时候需要一个析构器(Deinitializer),在类的实例被释放之前会调用析构器来清理类的实例。析构的更多信息会在下一个章节中呈现。

1. Setting Initial Value for Stored Property (为存储属性设定初始值)

要为类和结构体的存储属性设置一个初始值,这样才能创建类和结构体的实例。结构体和类的存储属性的状态不能为未知状态。可以在构造器里面为类和结构体设置一个初始值。或者设置一个默认的初始值作为类或结构体定义的一部分。

1.1 Initializer (构造器)

调用构造器就是为创建特殊类型的实例,构造器最简单的形式就是像一个没有参数的实例方法(Instance method),用init关键字介绍并引出这个构造器。

init() {
    // perform some initialization here
}

下面这个例子就是定义一个新的结构体Fahrenheit,该结构体中有一个注释了类型(Double)的变量temperature,用构造器给这个结构体的定义变量去赋值32。那么这个变量的初始值就是32了。只有在结构体的存储属性里面赋值之后,才能创建实例调用这个结构体里的存储属性。 根据上面的简介,还有一种就是直接给这个变量赋值也可以在创建实例的时候调用属性。

// 方法1
struct Fahrenheit {
    var temperature: Double
    // 用构造器来设定一个初始值
    init() {
        temperature = 32.0
    }
}
// 实例化后的调用 必须在构造器初始化值之后
var f = Fahrenheit()
// f.temperature f是实例名,用实例名引用结构体中的属性
print("The default temperature is \(f.temperature)° Fahrenheit")
// 输出:The default temperature is 32.0° Fahrenheit

1.2 Default Property Values (默认属性值)

可以在构造器中给存储属性设置一个初始值用来作为结构体定义的一部分。

// 方法2
struct Fahrenheit {
    var temperature: Double = 32.0
}
var f = Fahrenheit()
print("The default temperature is \(f.temperature)° Fahrenheit")

2. Customizing Initialization (自定义构造)

可以用输入参数和可选类型(Optional Type),或者分配一个常量属性在构造过程中的方式来自定义构造。下面会有详细描述介绍自定义构造的过程步骤。

2.1 Initialization Parameter (构造参数)

可以在构造器的定义中以提供构造参数的方式来作为来实现自定义构造这个过程。定义类型名称和值名称以此来实现自定义构造。构造参数它与函数参数和方法参数有着相同的功能和语法。

下面的定义了一个新的结构体Celsius,该结构体是实现了两个自定义的构造器init(fromFahrenheit:)init(fromKelvin:),构造了结构体的一个新的实例,分别通过不同的温度值范围来创建这个结构体的属性。

struct Celsius {
    var temperatureInCelsius: Double
    init(fromFahrenheit fahrenheit: Double) {
        temperatureInCelsius = (fahrenheit - 32.0) / 1.8
    }
    init(fromKelvin kelvin: Double) {
        temperatureInCelsius = kelvin - 273.15
    }
}
let boilingPointOfWater = Celsius(fromFahrenheit: 212.0)
// boilingPointOfWater的值就是(212.0-32.0)/1.8也就是100
let freezingPointOfWater = Celsius(fromKelvin: 273.15)

结构体有两个构造器,构造器1有一个构造参数是由实参标签fromFahrenheit参数名fahrenheit 组成。构造器2同样也有一个构造参数它是由实参标签fromKelvin参数名kelvin 组成。而两个构造器的构造参数都是Double类型的。最后这两个构造器都会转化构造参数给结构体的存储属性emperatureInCelsius

扫描二维码关注公众号,回复: 11591992 查看本文章

2.2 Parameter Names and Argument Labels (参数名和实参标签)。

前面的这个代码案例已经解释过实参标签和参数名了。就像在前面章节中的函数参数,方法参数和构造参数都可以在构造器的定义中使用实参标签和参数名的。当我们在调用构造器的时候。

然而,构造器并不像函数和方法那样在括号前有一个可辨别的名字。因此在调用构造器时,主要通过构造器中的参数名和类型来确定应该被调用的构造器。正因为类型的构造器名称如此重要,如果你在定义构造器时没有提供实参标签,Swift会自动为构造器的每个构造参数提供一个实参标签。

下面这个例子定义了一个结构体Color,有三种不同的颜色元素(redgreenblue)的常量属性。结构体中有两个构造器用来承载颜色,构造器1有三种颜色元素Double类型的red,green,和blue颜色。构造器2是有一种颜色元素的Double类型的white。这个white是一个为三种不同颜色元素提供相同颜色值的名字。指代的是不同的构造器,但构造器里面的构造参数是相同的。

struct Color {
    let red, green, blue: Double
    // red - argument label 
    // Double - paramenter type
    init(red: Double, green: Double, blue: Double) {
        self.red   = red
        self.green = green
        self.blue  = blue
    }
    init(white: Double) {
        red   = white
        green = white
        blue  = white
    }
}

这两个不同的构造器可以用来创建一个新的Color实例,通过给每个构造器提供一个已知的double类型的颜色值(也就是1.0,0.0,1.0)

				// red - argument label 
				// 1.0 - parameter value
let magenta = Color(red: 1.0, green: 0.0, blue: 1.0)
let halfGray = Color(white: 0.5)

注意,每次调用实例化后的构造器的时候,通过使用实参标签都要对以定义好的构造器来进行调用。也就是说要想调用构造器就不能在实例化后传递参数给构造器的时候省略掉实参标签。如果像相面这个例子那样省略掉实参标签的话 编译器就会报错。

let veryGreen = Color(0.0, 1.0, 0.0)
// 省略了实参标签 编译的时候会报错。

2.3 Initializer Parameters Without Argument Labels (无实参标签的构造器参数)

如果我们不想在某个v构造器的构造参数里面使用一个具体的实参标签可以用_替代具体的实参标签。这一点和函数里面不想使用实参标签是一样的。

struct Celsius {
    var temperatureInCelsius: Double
    init(fromFahrenheit fahrenheit: Double) {
        temperatureInCelsius = (fahrenheit - 32.0) / 1.8
    }
    init(fromKelvin kelvin: Double) {
        temperatureInCelsius = kelvin - 273.15
    }
    // 这里省略了实参标签
    init(_ celsius: Double) {
        temperatureInCelsius = celsius
    }
}
let bodyTemperature = Celsius(37.0)

2.4 Optional Property Type (可选属性类型)

如果我们自定义的一个类型有一个存储型属性,这个存储型属性逻辑上是可以没有值,很大程度上 这个值在构造过程中不能被设置,或者是因为这个值在这个点不允许有值。所以针对这种情况我们要在定义属性的时候,把这个类型的值定义为可选的类型,这个时候可选类型的值就会被自定初始化为一个nil的值了。说明了这个值在构造过程或初始化的时候可愈允许处于无值状态。

下面这个例子定义了一个类SurveyQuestion和一个String?类型的属性response

class SurveyQuestion {
    var text: String
    var response: String?
    init(text: String) {
        self.text = text
    }
    func ask() {
        print(text)
    }
}
let cheeseQuestion = SurveyQuestion(text: "Do you like cheese?")
// 调用函数ask (ask是一个)
cheeseQuestion.ask()
// 实例名用dot语法来读取/设置类型的属性
cheeseQuestion.response = "Yes, I do like cheese."

2.5 Assigning Constant Properties During Initialization (在构造中分配常量属性)

我们可以在构造的过程中的任何点给常量属性重新分配一个合适的值,只有在构造的时候给他设置过确定的值之后。一旦某个常量属性被分配了一个值之后,可以在将来对该常量属性进行修改。

把上述例子中的变量属性用作常量属性,来指明这个question在实例创建之后不做修改。依旧还可以在这个类的构造器中,设置问题的text属性的类型(变量或常量属性)。

class SurveyQuestion {
    let text: String
    var response: String?
    init(text: String) {
        self.text = text
    }
    func ask() {
        print(text)
    }
}
let beetsQuestion(text: "How about beets?")
beetQuestion.ask()
// 输出:How about beets?
beetsQuestion.response = "I also like beets. (But not with cheese.)"

猜你喜欢

转载自blog.csdn.net/weixin_45026183/article/details/105654331
今日推荐