Update 14_Initialization.md

This commit is contained in:
Wang Ming
2015-07-24 15:45:28 +08:00
parent 7edc0faa57
commit 21306131c0

View File

@ -717,13 +717,13 @@ if anonymousCreature == nil {
```
> 注意:
空字符串(```""```)和一个值为```nil```的可选类型的字符串是两个完全不同的概念。上例中的空字符串(`""`)其实是一个有效的,非可选类型的字符串。这里我们只所以让`Animal`的可失败构造器,构建对象失败,只是因为对于`Animal`这个类的`species`属性来说,它更适合有一个具体的值,而不是空字符串。
空字符串(`""`)和一个值为`nil`的可选类型的字符串是两个完全不同的概念。上例中的空字符串(`""`)其实是一个有效的,非可选类型的字符串。这里我们只所以让`Animal`的可失败构造器,构建对象失败,只是因为对于`Animal`这个类的`species`属性来说,它更适合有一个具体的值,而不是空字符串。
###枚举类型的可失败构造器
你可以通过构造一个带一个或多个参数的可失败构造器来获取枚举类型中特定的枚举成员。还能在参数不满足你所期望的条件时,导致构造失败。
下例中定义了一个名为TemperatureUnit的枚举类型。其中包含了三个可能的枚举成员(```Kelvin``````Celsius```,和 ```Fahrenheit```)和一个被用来找到```Character```值所对应的枚举成员的可失败构造器:
下例中定义了一个名为TemperatureUnit的枚举类型。其中包含了三个可能的枚举成员(`Kelvin``Celsius`,和 `Fahrenheit`)和一个被用来找到`Character`值所对应的枚举成员的可失败构造器:
```swift
enum TemperatureUnit {
@ -761,7 +761,7 @@ if unknownUnit == nil {
###带原始值的枚举类型的可失败构造器
带原始值的枚举类型会自带一个可失败构造器```init?(rawValue:)```,该可失败构造器有一个名为```rawValue```的默认参数,其类型和枚举类型的原始值类型一致,如果该参数的值能够和枚举类型成员所带的原始值匹配,则该构造器构造一个带此原始值的枚举成员,否则构造失败。
带原始值的枚举类型会自带一个可失败构造器`init?(rawValue:)`,该可失败构造器有一个名为`rawValue`的默认参数,其类型和枚举类型的原始值类型一致,如果该参数的值能够和枚举类型成员所带的原始值匹配,则该构造器构造一个带此原始值的枚举成员,否则构造失败。
因此上面的 TemperatureUnit的例子可以重写为
@ -785,9 +785,9 @@ if unknownUnit == nil {
###类的可失败构造器
值类型(如结构体或枚举类型)的可失败构造器,对何时何地触发构造失败这个行为没有任何的限制。比如在前面的例子中,结构体```Animal```的可失败构造器触发失败的行为,甚至发生在`species`属性的值被初始化以前。而对类而言,就没有那么幸运了。类的可失败构造器只能在所有的类属性被初始化后和所有类之间的构造器之间的代理调用发生完后触发失败行为。
值类型(如结构体或枚举类型)的可失败构造器,对何时何地触发构造失败这个行为没有任何的限制。比如在前面的例子中,结构体`Animal`的可失败构造器触发失败的行为,甚至发生在`species`属性的值被初始化以前。而对类而言,就没有那么幸运了。类的可失败构造器只能在所有的类属性被初始化后和所有类之间的构造器之间的代理调用发生完后触发失败行为。
下例子中,定义了一个名为```Product```的类,其内部结构和结构体```Animal```很相似,内部也有一个名为```name```的```String```类型的属性。由于该属性的值同样不能为空字符串,所以我们加入了可失败构造器来确保该类满足上述条件。但由于```Product```类不是一个结构体,所以当想要在该类中添加可失败构造器触发失败条件时,必须确保```name```属性被初始化。因此我们把```name```属性的```String```类型做了一点点小小的修改,把其改为隐式解析可选类型(```String!```),来确保可失败构造器触发失败条件时,所有类属性都被初始化了。因为所有可选类型都有一个默认的初始值```nil```。因此最后```Product```类可写为:
下例子中,定义了一个名为`Product`的类,其内部结构和结构体`Animal`很相似,内部也有一个名为`name``String`类型的属性。由于该属性的值同样不能为空字符串,所以我们加入了可失败构造器来确保该类满足上述条件。但由于`Product`类不是一个结构体,所以当想要在该类中添加可失败构造器触发失败条件时,必须确保`name`属性被初始化。因此我们把`name`属性的`String`类型做了一点点小小的修改,把其改为隐式解析可选类型(`String!`),来确保可失败构造器触发失败条件时,所有类属性都被初始化了。因为所有可选类型都有一个默认的初始值`nil`。因此最后`Product`类可写为:
```swift
class Product {
@ -799,7 +799,7 @@ class Product {
}
```
因为```name```属性是一个常量,所以一旦```Product```类构造成功,```name```属性肯定有一个非```nil```的值。因此完全可以放心大胆的直接访问```Product```类的```name```属性,而不用考虑去检查```name```属性是否有值。
因为`name`属性是一个常量,所以一旦`Product`类构造成功,`name`属性肯定有一个非`nil`的值。因此完全可以放心大胆的直接访问`Product`类的`name`属性,而不用考虑去检查`name`属性是否有值。
```swift
if let bowTie = Product(name: "bow tie") {
@ -818,7 +818,7 @@ if let bowTie = Product(name: "bow tie") {
>注意:
可失败构造器也可以代理调用其它的非可失败构造器。通过这个方法,你可以为已有的构造过程加入构造失败的条件。
下面这个例子,定义了一个名为```CartItem```的```Product```类的子类。这个类建立了一个在线购物车中的物品的模型,它有一个名为```quantity```的常量参数用来表示该物品的数量至少为1
下面这个例子,定义了一个名为`CartItem``Product`类的子类。这个类建立了一个在线购物车中的物品的模型,它有一个名为`quantity`的常量参数用来表示该物品的数量至少为1
```swift
class CartItem: Product {
@ -831,13 +831,13 @@ class CartItem: Product {
}
```
和```Product```类中的```name```属性相类似的,```CartItem```类中的```quantity```属性的类型也是一个隐式解析可选类型,只不过由(```String```)变为了(```Int!```。这样做都是为了确保在构造过程中该属性在被赋予特定的值之前能有一个默认的初始值nil。
`Product`类中的`name`属性相类似的,`CartItem`类中的`quantity`属性的类型也是一个隐式解析可选类型,只不过由(`String!`)变为了(`Int!`。这样做都是为了确保在构造过程中该属性在被赋予特定的值之前能有一个默认的初始值nil。
可失败构造器总是先向上代理调用基类,```Product```的构造器 ```init(name:)```。这满足了可失败构造器在触发构造失败这个行为前必须总是执行构造代理调用这个条件。
可失败构造器总是先向上代理调用基类,`Product`的构造器 `init(name:)`。这满足了可失败构造器在触发构造失败这个行为前必须总是执行构造代理调用这个条件。
如果由于```name```的值为空而导致基类的构造器在构造过程中失败。则整个`CartIem`类的构造过程都将失败,后面的子类的构造过程都将不会被执行。如果基类构建成功,则继续运行子类的构造器代码。
如果由于`name`的值为空而导致基类的构造器在构造过程中失败。则整个`CartIem`类的构造过程都将失败,后面的子类的构造过程都将不会被执行。如果基类构建成功,则继续运行子类的构造器代码。
如果你构造了一个```CartItem```对象,并且该对象的```name```属性不为空以及```quantity```属性为1或者更多则构造成功
如果你构造了一个`CartItem`对象,并且该对象的`name`属性不为空以及`quantity`属性为1或者更多则构造成功
```swift
if let twoSocks = CartItem(name: "sock", quantity: 2) {
@ -845,7 +845,7 @@ if let twoSocks = CartItem(name: "sock", quantity: 2) {
}
// 打印 "Item: sock, quantity: 2"
```
如果你构造一个```CartItem```对象,其```quantity```的值```0```, 则```CartItem```的可失败构造器触发构造失败的行为:
如果你构造一个`CartItem`对象,其`quantity`的值`0`, 则`CartItem`的可失败构造器触发构造失败的行为:
```swift
if let zeroShirts = CartItem(name: "shirt", quantity: 0) {
@ -856,7 +856,7 @@ if let zeroShirts = CartItem(name: "shirt", quantity: 0) {
// 打印 "Unable to initialize zero shirts"
```
类似的, 如果你构造一个```CartItem```对象,但其```name```的值为空, 则基类```Product```的可失败构造器将触发构造失败的行为,整个```CartItem```的构造行为同样为失败:
类似的, 如果你构造一个`CartItem`对象,但其`name`的值为空, 则基类`Product`的可失败构造器将触发构造失败的行为,整个`CartItem`的构造行为同样为失败:
```swift
if let oneUnnamed = CartItem(name: "", quantity: 1) {
@ -876,7 +876,7 @@ if let oneUnnamed = CartItem(name: "", quantity: 1) {
>注意:
你可以用一个非可失败构造器重写一个可失败构造器,但反过来却行不通。
下例定义了一个名为```Document```的类,这个类中的```name```属性允许为```nil```和一个非空字符串,但不能是一个空字符串:
下例定义了一个名为`Document`的类,这个类中的`name`属性允许为`nil`和一个非空字符串,但不能是一个空字符串:
```swift
class Document {
@ -891,7 +891,7 @@ class Document {
}
```
下面这个例子,定义了一个名为```AutomaticallyNamedDocument```的```Document```类的子类。这个子类重写了基类的两个指定构造器。确保了不论在何种情况下```name```属性总是有一个非空字符串```[Untitled]```的值。
下面这个例子,定义了一个名为`AutomaticallyNamedDocument``Document`类的子类。这个子类重写了基类的两个指定构造器。确保了不论在何种情况下`name`属性总是有一个非空字符串`[Untitled]`的值。
```swift
class AutomaticallyNamedDocument: Document {
@ -910,20 +910,20 @@ class AutomaticallyNamedDocument: Document {
}
```
```AutomaticallyNamedDocument```用一个非可失败构造器```init(name:)```,重写了基类的可失败构造器```init?(name:)```。因为子类用不同的方法处理了```name```属性的值为一个空字符串的这种情况。所以子类将不再需要一个可失败的构造器。
`AutomaticallyNamedDocument`用一个非可失败构造器`init(name:)`,重写了基类的可失败构造器`init?(name:)`。因为子类用不同的方法处理了`name`属性的值为一个空字符串的这种情况。所以子类将不再需要一个可失败的构造器。
###可失败构造器 init!
通常来说我们通过在```init```关键字后添加问号的方式来定义一个可失败构造器,但你也可以使用通过在```init```后面添加惊叹号的方式来定义一个可失败构造器```init!```,该可失败构造器将会构建一个特定类型的隐式解析可选类型的对象。
通常来说我们通过在`init`关键字后添加问号的方式来定义一个可失败构造器,但你也可以使用通过在`init`后面添加惊叹号的方式来定义一个可失败构造器`(init!)`,该可失败构造器将会构建一个特定类型的隐式解析可选类型的对象。
你可以在 ```init```构造器中代理调用 ```init```构造器,反之亦然。
你也可以用 ```init```重写 ```init```,反之亦然。
你还可以用 ```init```代理调用```init```,但这会触发一个断言:是否 ```init```构造器会触发构造失败?
你可以在 `init? `构造器中代理调用 `init!`构造器,反之亦然。
你也可以用 `init?`重写 `init!`,反之亦然。
你还可以用 `init`代理调用`init!`,但这会触发一个断言:是否 `init!` 构造器会触发构造失败?
<a name="required_initializers"></a>
##必要构造器
在类的构造器前添加```required```修饰符表明所有该类的子类都必须实现该构造器:
在类的构造器前添加 `required` 修饰符表明所有该类的子类都必须实现该构造器:
```swift
class SomeClass {
@ -932,7 +932,7 @@ class SomeClass {
}
}
```
当子类重写基类的必要构造器时,必须在子类的构造器前同样添加```required```修饰符以确保当其它类继承该子类时,该构造器同为必要构造器。在重写基类的必要构造器时,不需要添加```override```修饰符:
当子类重写基类的必要构造器时,必须在子类的构造器前同样添加`required`修饰符以确保当其它类继承该子类时,该构造器同为必要构造器。在重写基类的必要构造器时,不需要添加`override`修饰符:
```swift
class SomeSubclass: SomeClass {