Merge branch 'develop' into gh-pages
This commit is contained in:
@ -609,7 +609,7 @@ if convertedNumber != nil {
|
||||
<a name="optional_binding"></a>
|
||||
### 可选绑定
|
||||
|
||||
使用可选绑定(optional binding)来判断可选类型是否包含值,如果包含就把值赋给一个临时常量或者变量。可选绑定可以用在`if`和`while`语句中来对可选类型的值进行判断并把值赋给一个常量或者变量。`if`和`while`语句,请参考[控制流](./05_Control_Flow.html)。
|
||||
使用可选绑定(optional binding)来判断可选类型是否包含值,如果包含就把值赋给一个临时常量或者变量。可选绑定可以用在`if`和`while`语句中,这条语句不仅可以用来判断可选类型中是否有值,同时可以将可选类型中的值赋给一个常量或者变量。`if`和`while`语句,请参考[控制流](./05_Control_Flow.html)。
|
||||
|
||||
像下面这样在`if`语句中写一个可选绑定:
|
||||
|
||||
@ -771,6 +771,9 @@ assert(age >= 0, "A person's age cannot be less than zero")
|
||||
assert(age >= 0)
|
||||
```
|
||||
|
||||
> 注意:
|
||||
当代码使用优化编译的时候,断言将会被禁用,例如在 Xcode 中,使用默认的 target Release 配置选项来 build 时,断言会被禁用。
|
||||
|
||||
### 何时使用断言
|
||||
|
||||
当条件可能为假时使用断言,但是最终一定要_保证_条件为真,这样你的代码才能继续运行。断言的适用情景:
|
||||
|
||||
@ -312,7 +312,7 @@ if hasHeader {
|
||||
- 表达式`a`必须是Optional类型
|
||||
- 默认值`b`的类型必须要和`a`存储值的类型保持一致
|
||||
|
||||
空合并运算符是对以下代码的简短表达方法
|
||||
空合运算符是对以下代码的简短表达方法
|
||||
|
||||
```swift
|
||||
a != nil ? a! : b
|
||||
@ -323,7 +323,7 @@ a != nil ? a! : b
|
||||
> 注意:
|
||||
如果`a`为非空值(`non-nil`),那么值`b`将不会被估值。这也就是所谓的短路求值。
|
||||
|
||||
下文例子采用空合并运算符,实现了在默认颜色名和可选自定义颜色名之间抉择:
|
||||
下文例子采用空合运算符,实现了在默认颜色名和可选自定义颜色名之间抉择:
|
||||
|
||||
```swift
|
||||
let defaultColorName = "red"
|
||||
|
||||
@ -24,18 +24,18 @@
|
||||
- [字符串的 Unicode 表示形式](#unicode_representations_of_strings)
|
||||
|
||||
|
||||
`String`是例如"hello, world","albatross"这样的有序的`Character`(字符)类型的值的集合,通过`String`类型来表示。
|
||||
Swift 的`String`和`Character`类型提供了一个快速的,兼容 Unicode 的方式来处理代码中的文本。
|
||||
`String`是例如"hello, world","albatross"这样的有序的`Character`(字符)类型的值的集合。通过`String`类型来表示。
|
||||
一个`String`的内容可以用变量的方式读取,它包括一个`Character`值的集合。
|
||||
创建和操作字符串的语法与 C 语言中字符串操作相似,轻量并且易读。
|
||||
字符串连接操作只需要简单地通过`+`符号将两个字符串相连即可。
|
||||
与 Swift 中其他值一样,能否更改字符串的值,取决于其被定义为常量还是变量。
|
||||
与 Swift 中其他值一样,能否更改字符串的值,取决于其被定义为常量还是变量。你也可以在字符串内插过程中使用字符串插入常量、变量、字面量表达成更长的字符串,这样可以很容易的创建自定义的字符串值,进行展示、存储以及打印。
|
||||
尽管语法简易,但`String`类型是一种快速、现代化的字符串实现。
|
||||
每一个字符串都是由编码无关的 Unicode 字符组成,并支持访问字符的多种 Unicode 表示形式(representations)。
|
||||
你也可以在常量、变量、字面量和表达式中进行字符串插值操作,这可以帮助你轻松创建用于展示、存储和打印的自定义字符串。
|
||||
|
||||
> 注意:
|
||||
> Swift 的`String`类型与 Foundation `NSString`类进行了无缝桥接。就像 [`AnyObject`类型](./19_Type_Casting.html#anyobject) 中提到的一样,在使用 Cocoa 中的 Foundation 框架时,您可以将创建的任何字符串的值转换成`NSString`,并调用任意的`NSString` API。您也可以在任意要求传入`NSString`实例作为参数的 API 中用`String`类型的值代替。
|
||||
> 更多关于在 Foundation 和 Cocoa 中使用`String`的信息请查看 *[Using Swift with Cocoa and Objective-C](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/index.html#//apple_ref/doc/uid/TP40014216)*。
|
||||
> 更多关于在 Foundation 和 Cocoa 中使用`String`的信息请查看 *[Using Swift with Cocoa and Objective-C (Swift 2)](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/index.html#//apple_ref/doc/uid/TP40014216)*。
|
||||
|
||||
|
||||
|
||||
@ -101,9 +101,6 @@ Swift 的`String`类型是值类型。
|
||||
任何情况下,都会对已有字符串值创建新副本,并对该新副本进行传递或赋值操作。
|
||||
值类型在 [结构体和枚举是值类型](./09_Classes_and_Structures.html#structures_and_enumerations_are_value_types) 中进行了详细描述。
|
||||
|
||||
> 注意:
|
||||
与 Cocoa 中的`NSString`不同,当您在 Cocoa 中创建了一个`NSString`实例,并将其传递给一个函数/方法,或者赋值给一个变量,您传递或赋值的是该`NSString`实例的一个引用,除非您特别要求进行值拷贝,否则字符串不会生成新的副本来进行赋值操作。
|
||||
|
||||
Swift 默认字符串拷贝的方式保证了在函数/方法中传递的是字符串的值。
|
||||
很明显无论该值来自于哪里,都是您独自拥有的。
|
||||
您可以确信传递的字符串不会被修改,除非你自己去修改它。
|
||||
|
||||
@ -14,6 +14,8 @@
|
||||
- [While 循环](#while_loops)
|
||||
- [条件语句](#conditional_statement)
|
||||
- [控制转移语句(Control Transfer Statements)](#control_transfer_statements)
|
||||
- [提前退出](#early_exit)
|
||||
- [检测API是否可用](#checking_api_availability)
|
||||
|
||||
Swift提供了类似 C 语言的流程控制结构,包括可以多次执行任务的`for`和`while`循环,基于特定条件选择执行不同代码分支的`if`、`guard`和`switch`语句,还有控制流程跳转到其他代码的`break`和`continue`语句。
|
||||
|
||||
@ -713,7 +715,7 @@ print("Game over!")
|
||||
同时请注意,当调用`continue gameLoop`去跳转到下一次循环迭代时,这里使用`gameLoop`标签并不是严格必须的。因为在这个游戏中,只有一个循环体,所以`continue`语句会影响到哪个循环体是没有歧义的。然而,`continue`语句使用`gameLoop`标签也是没有危害的。这样做符合标签的使用规则,同时参照旁边的`break gameLoop`,能够使游戏的逻辑更加清晰和易于理解。
|
||||
|
||||
<a name="early_exit"></a>
|
||||
### 提前退出
|
||||
## 提前退出
|
||||
|
||||
像`if`语句一样,`guard`的执行取决于一个表达式的布尔值。我们可以使用`guard`语句来要求条件必须为真时,以执行`guard`语句后的代码。不同于`if`语句,一个`guard`语句总是有一个`else`分句,如果条件不为真则执行`else`分局中的代码。
|
||||
|
||||
@ -746,7 +748,7 @@ greet(["name": "Jane", "location": "Cupertino"])
|
||||
它可以使你的代码连贯的被执行而不需要将它包在`else`块中,它可以使你处理违反要求的代码接近要求。
|
||||
|
||||
<a name="checking_api_availability"></a>
|
||||
### 检测API是否可用
|
||||
## 检测API是否可用
|
||||
|
||||
Swift 有内置支持去检查接口的可用性的,这可以确保我们不会不小心地使用对于当前部署目标不可用的API。
|
||||
|
||||
|
||||
@ -333,8 +333,7 @@ arithmeticMean(3, 8.25, 18.75)
|
||||
```
|
||||
|
||||
> 注意:
|
||||
> 最多可以有一个可变参数函数,和它必须出现在参数列表中,为了避免歧义在调用函数有多个参数。
|
||||
> 如果你的函数有一个或多个参数有默认值,还有一个可变的参数,将可变参写在参数列表的最后。
|
||||
> 一个函数最多只能有一个可变参数。
|
||||
|
||||
如果函数有一个或多个带默认值的参数,而且还有一个可变参数,那么把可变参数放在参数表的最后。
|
||||
|
||||
|
||||
@ -16,13 +16,13 @@
|
||||
- [原始值(Raw Values)](#raw_values)
|
||||
- [递归枚举(Recursive Enumerations)](#recursive_enumerations)
|
||||
|
||||
*枚举*定义了一个通用类型的一组相关值,使你可以在你的代码中以一种安全的方式来使用这些值。
|
||||
**枚举**定义了一个通用类型的一组相关值,使你可以在你的代码中以一种安全的方式来使用这些值。
|
||||
|
||||
如果你熟悉 C 语言,你就会知道,在 C 语言中枚举将枚举名和一个整型值相对应。Swift 中的枚举更加灵活,不必给每一个枚举成员提供一个值。如果给枚举成员提供一个值(称为“原始”值),则该值的类型可以是字符串,字符,或是一个整型值或浮点数。
|
||||
|
||||
此外,枚举成员可以指定任何类型的相关值存储到枚举成员值中,就像其他语言中的联合体(unions)和变体(variants)。你可以定义一组通用的相关成员作为枚举的一部分,每一组都有不同的一组与它相关的适当类型的数值。
|
||||
|
||||
在 Swift 中,枚举类型是一等公民(first-class)。它们采用了很多传统上只被类(class)所支持的特征,例如计算型属性(computed properties),用于提供关于枚举当前值的附加信息, 实例方法(instance methods),用于提供和枚举所代表的值相关联的功能。枚举也可以定义构造函数(initializers)来提供一个初始值;可以在原始的实现基础上扩展它们的功能;可以遵守协议(protocols)来提供标准的功能。
|
||||
在 Swift 中,枚举类型是一等公民(first-class)。它们采用了很多传统上只被类(class)所支持的特征,例如计算型属性(computed properties),用于提供关于枚举当前值的附加信息,实例方法(instance methods),用于提供和枚举所代表的值相关联的功能。枚举也可以定义构造函数(initializers)来提供一个初始值;可以在原始的实现基础上扩展它们的功能;可以遵守协议(protocols)来提供标准的功能。
|
||||
|
||||
欲了解更多相关信息,请参见[属性(Properties)](./10_Properties.html),[方法(Methods)](./11_Methods.html),[构造过程(Initialization)](./14_Initialization.html),[扩展(Extensions)](./20_Extensions.html)和[协议(Protocols)](./21_Protocols.html)。
|
||||
|
||||
@ -33,11 +33,11 @@
|
||||
|
||||
```swift
|
||||
enum SomeEnumeration {
|
||||
// enumeration definition goes here
|
||||
// 枚举定义放在这里
|
||||
}
|
||||
```
|
||||
|
||||
以下是指南针四个方向的一个例子:
|
||||
下面是指南针四个方向的例子:
|
||||
|
||||
```swift
|
||||
enum CompassPoint {
|
||||
@ -48,10 +48,10 @@ enum CompassPoint {
|
||||
}
|
||||
```
|
||||
|
||||
一个枚举中被定义的值(例如 `North`,`South`,`East`和`West`)是枚举的*成员值*(或者*成员*)。`case`关键词表明新的一行成员值将被定义。
|
||||
枚举中定义的值(如 `North`,`South`,`East`和`West`)是这个枚举的**成员值**(或**成员**)。`case`关键词表示一行新的成员值将被定义。
|
||||
|
||||
> 注意:
|
||||
> 和 C 和 Objective-C 不同,Swift 的枚举成员在被创建时不会被赋予一个默认的整型值。在上面的`CompassPoints`例子中,`North`,`South`,`East`和`West`不会隐式地赋值为了`0`,`1`,`2`和`3`。相反的,这些不同的枚举成员在`CompassPoint`的一种显示定义中拥有各自不同的值。
|
||||
> 和 C 和 Objective-C 不同,Swift 的枚举成员在被创建时不会被赋予一个默认的整型值。在上面的`CompassPoint`例子中,`North`,`South`,`East`和`West`不会隐式地赋值为`0`,`1`,`2`和`3`。相反,这些枚举成员本身就有完备的值,这些值是已经明确定义好的`CompassPoint`类型。
|
||||
|
||||
多个成员值可以出现在同一行上,用逗号隔开:
|
||||
|
||||
@ -83,13 +83,13 @@ directionToHead = .East
|
||||
```swift
|
||||
directionToHead = .South
|
||||
switch directionToHead {
|
||||
case .North:
|
||||
case .North:
|
||||
print("Lots of planets have a north")
|
||||
case .South:
|
||||
case .South:
|
||||
print("Watch out for penguins")
|
||||
case .East:
|
||||
case .East:
|
||||
print("Where the sun rises")
|
||||
case .West:
|
||||
case .West:
|
||||
print("Where the skies are blue")
|
||||
}
|
||||
// 输出 "Watch out for penguins”
|
||||
@ -119,19 +119,19 @@ default:
|
||||
<a name="associated_values"></a>
|
||||
## 相关值(Associated Values)
|
||||
|
||||
上一小节的例子演示了如何定义(分类)枚举的成员。你可以为`Planet.Earth`设置一个常量或者变量,并且在赋值之后查看这个值。不管怎样,如果有时候能够把其他类型的*相关值*和成员值一起存储起来会很有用。这能让你存储成员值之外的自定义信息,并且当你每次在代码中使用该成员时允许这个信息产生变化。
|
||||
上一小节的例子演示了如何定义(分类)枚举的成员。你可以为`Planet.Earth`设置一个常量或者变量,并且在赋值之后查看这个值。不管怎样,如果有时候能够把其他类型的**相关值**和成员值一起存储起来会很有用。这能让你存储成员值之外的自定义信息,并且当你每次在代码中使用该成员时允许这个信息产生变化。
|
||||
|
||||
你可以定义 Swift 的枚举存储任何类型的相关值,如果需要的话,每个成员的数据类型可以是各不相同的。枚举的这种特性跟其他语言中的可辨识联合(discriminated unions),标签联合(tagged unions),或者变体(variants)相似。
|
||||
|
||||
例如,假设一个库存跟踪系统需要利用两种不同类型的条形码来跟踪商品。有些商品上标有 UPC-A 格式的一维t条形码,它使用数字 0 到 9。每一个条形码都有一个代表“数字系统”的数字,该数字后接 5 个代表“生产代码”的数字,接下来是5位“产品代码”。最后一个数字是“检查”位,用来验证代码是否被正确扫描:
|
||||
例如,假设一个库存跟踪系统需要利用两种不同类型的条形码来跟踪商品。有些商品上标有 UPC-A 格式的一维条形码,它使用数字 0 到 9。每一个条形码都有一个代表“数字系统”的数字,该数字后接 5 个代表“生产代码”的数字,接下来是5位“产品代码”。最后一个数字是“检查”位,用来验证代码是否被正确扫描:
|
||||
|
||||
<img width="252" height="120" alt="" src="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/barcode_UPC_2x.png">
|
||||
|
||||
其他商品上标有 QR 码格式的二维码,它可以使用任何 ISO8859-1 字符,并且可以编码一个最多拥有 2,953 字符的字符串:
|
||||
其他商品上标有 QR 码格式的二维码,它可以使用任何 ISO 8859-1 字符,并且可以编码一个最多拥有 2953 个字符的字符串:
|
||||
|
||||
<img width="169" height="169" alt="" src="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/barcode_QR_2x.png">
|
||||
|
||||
对于库存跟踪系统来说,能够把 UPC-A 码作为三个整型值的元组,和把 QR 码作为一个任何长度的字符串存储起来是方便的。
|
||||
对于库存跟踪系统来说,能够把 UPC-A 码作为四个整型值的元组,和把 QR 码作为一个任何长度的字符串存储起来是方便的。
|
||||
|
||||
在 Swift 中,使用如下方式定义两种商品条码的枚举:
|
||||
|
||||
@ -229,7 +229,7 @@ enum Planet: Int {
|
||||
|
||||
当使用字符串作为枚举类型的初值时,每个枚举成员的隐式初值则为该成员的名称。
|
||||
|
||||
下面的例子是`CompassPoint`枚举类型的精简版,使用字符串作为初值类型,隐式初始化为咩个方向的名称:
|
||||
下面的例子是`CompassPoint`枚举类型的精简版,使用字符串作为初值类型,隐式初始化为各个方向的名称:
|
||||
|
||||
```swift
|
||||
enum CompassPoint: String {
|
||||
@ -248,11 +248,10 @@ let earthsOrder = Planet.Earth.rawValue
|
||||
let sunsetDirection = CompassPoint.West.rawValue
|
||||
// sunsetDirection 值为 "West"
|
||||
```
|
||||
### 使用原始值来初始化(Initializing from a Raw Value)
|
||||
|
||||
### 使用原始值初始化枚举变量(Initializing from a Raw Value)
|
||||
|
||||
如果在定义枚举类型的时候使用了原始值,那么将会自动获得一个初始化方法,这个方法将原始值类型作为参数,返回枚举成员或者`nil`。你可以使用这种初始化方法来创建一个新的枚举变量。
|
||||
如果在定义枚举类型的时候使用了原始值,那么将会自动获得一个初始化方法,这个方法将原始值类型作为参数,返回值是枚举成员或`nil`。你可以使用这种初始化方法来创建一个新的枚举变量。
|
||||
|
||||
这个例子通过原始值`7`从而创建枚举成员:
|
||||
|
||||
@ -261,7 +260,7 @@ let possiblePlanet = Planet(rawValue: 7)
|
||||
// possiblePlanet 类型为 Planet? 值为 Planet.Uranus
|
||||
```
|
||||
|
||||
然而,并非所有可能的`Int`值都可以找到一个匹配的行星。正因为如此,构造函数可以返回一个*可选*的枚举成员。在上面的例子中,`possiblePlanet`是`Planet?`类型,或“可选的`Planet`”。
|
||||
然而,并非所有可能的`Int`值都可以找到一个匹配的行星。正因为如此,构造函数可以返回一个**可选**的枚举成员。在上面的例子中,`possiblePlanet`是`Planet?`类型,或“可选的`Planet`”。
|
||||
|
||||
>注意:
|
||||
>原始值构造器是一个可失败构造器,因为并不是每一个原始值都有与之对应的枚举成员。更多信息请参见[可失败构造器](../chapter3/05_Declarations#failable_initializers)
|
||||
@ -288,9 +287,9 @@ if let somePlanet = Planet(rawValue: positionToFind) {
|
||||
<a name="recursive_enumerations"></a>
|
||||
## 递归枚举(Recursive Enumerations)
|
||||
|
||||
在对操作符进行描述的时候,使用枚举类型来对数据建模很方便,因为需要考虑的情况固定可枚举。操作符可以将两个由数字组成的算数表达式连接起来,例如,将`5`连接成复杂一些的表达式`5+4`.
|
||||
在对操作符进行描述的时候,使用枚举类型来对数据建模很方便,因为需要考虑的情况固定可枚举。操作符可以将两个由数字组成的算数表达式连接起来,例如,将`5`连接成复杂一些的表达式`5+4`。
|
||||
|
||||
算数表达式的一个重要特性是,表达式可以嵌套使用。例如,表达式`(5 + 4) * 2`乘号右边是一个数字,左边则是另一个表达式。因为数据是嵌套的,因而用来存储数据的枚举类型也许要支持这种嵌套————这表示枚举类型需要支持递归。
|
||||
算术表达式的一个重要特性是,表达式可以嵌套使用。例如,表达式`(5 + 4) * 2`乘号右边是一个数字,左边则是另一个表达式。因为数据是嵌套的,因而用来存储数据的枚举类型也许要支持这种嵌套————这表示枚举类型需要支持递归。
|
||||
|
||||
`递归枚举(recursive enumeration)`是一种枚举类型,表示它的枚举中,有一个或多个枚举成员拥有该枚举的其他成员作为相关值。使用递归枚举时,编译器会插入一个中间层。你可以在枚举成员前加上`indirect`来表示这成员可递归。
|
||||
|
||||
@ -317,7 +316,7 @@ indirect enum ArithmeticExpression {
|
||||
|
||||
上面定义的枚举类型可以存储三种算数表达式:纯数字、两个表达式的相加、两个表达式相乘。`Addition` 和 `Multiplication`成员的相关值也是算数表达式————这些相关值使得嵌套表达式成为可能。
|
||||
|
||||
递归函数可以很直观地使用具有递归性质的数据结构。例如,下面是一个计算算数表达式的函数:
|
||||
递归函数可以很直观地使用具有递归性质的数据结构。例如,下面是一个计算算术表达式的函数:
|
||||
|
||||
```swift
|
||||
func evaluate(expression: ArithmeticExpression) -> Int {
|
||||
@ -340,4 +339,4 @@ print(evaluate(product))
|
||||
// 输出 "18"
|
||||
```
|
||||
|
||||
该函数如果遇到纯数字,就直接返回该数字的值。如果遇到的是加法或乘法元算,则分别计算左边表达式和右边表达式的值,然后相加或相乘。
|
||||
该函数如果遇到纯数字,就直接返回该数字的值。如果遇到的是加法或乘法运算,则分别计算左边表达式和右边表达式的值,然后相加或相乘。
|
||||
|
||||
@ -305,6 +305,7 @@ stepCounter.totalSteps = 896
|
||||
|
||||
> 注意:
|
||||
> 跟实例的存储属性不同,必须给存储型类型属性指定默认值,因为类型本身无法在初始化过程中使用构造器给类型属性赋值。
|
||||
> 存储型类型属性是延迟初始化的(lazily initialized),它们只有在第一次被访问的时候才会被初始化。即使它们被多个线程同时访问,系统也保证只会对其进行初始化一次,并且不需要对其使用 `lazy` 修饰符。
|
||||
|
||||
<a name="type_property_syntax"></a>
|
||||
###类型属性语法
|
||||
|
||||
@ -20,21 +20,21 @@
|
||||
- [通过闭包和函数来设置属性的默认值](#setting_a_default_property_value_with_a_closure_or_function)
|
||||
|
||||
|
||||
构造过程是为了使用某个类、结构体或枚举类型的实例而进行的准备过程。这个过程包含了为实例中的每个存储型属性设置初始值和为其执行必要的准备和初始化任务。
|
||||
构造过程是使用类、结构体或枚举类型一个实例的准备过程。在新实例可用前必须执行这个过程,具体操作包括设置实例中每个存储型属性的初始值和执行其他必须的设置或初始化工作。
|
||||
|
||||
构造过程是通过定义构造器(`Initializers`)来实现的,这些构造器可以看做是用来创建特定类型实例的特殊方法。与 Objective-C 中的构造器不同,Swift 的构造器无需返回值,它们的主要任务是保证新实例在第一次使用前完成正确的初始化。
|
||||
通过定义构造器(`Initializers`)来实现构造过程,这些构造器可以看做是用来创建特定类型新实例的特殊方法。与 Objective-C 中的构造器不同,Swift 的构造器无需返回值,它们的主要任务是保证新实例在第一次使用前完成正确的初始化。
|
||||
|
||||
类的实例也可以通过定义析构器(`deinitializer`)在实例释放之前执行特定的清除工作。想了解更多关于析构器的内容,请参考[析构过程](./15_Deinitialization.html)。
|
||||
|
||||
<a name="setting_initial_values_for_stored_properties"></a>
|
||||
## 存储型属性的初始赋值
|
||||
## 设置存储型属性的初始值
|
||||
|
||||
类和结构体在实例创建时,必须为所有存储型属性设置合适的初始值。存储型属性的值不能处于一个未知的状态。
|
||||
类和结构体在创建实例时,必须为所有存储型属性设置合适的初始值。存储型属性的值不能处于一个未知的状态。
|
||||
|
||||
你可以在构造器中为存储型属性赋初值,也可以在定义属性时为其设置默认值。以下章节将详细介绍这两种方法。
|
||||
你可以在构造器中为存储型属性赋初值,也可以在定义属性时为其设置默认值。以下小节将详细介绍这两种方法。
|
||||
|
||||
>注意:
|
||||
当你为存储型属性设置默认值或者在构造器中为其赋值时,它们的值是被直接设置的,不会触发任何属性观测器(`property observers`)。
|
||||
当你为存储型属性设置默认值或者在构造器中为其赋值时,它们的值是被直接设置的,不会触发任何属性观察者(`property observers`)。
|
||||
|
||||
### 构造器
|
||||
|
||||
@ -67,7 +67,7 @@ print("The default temperature is \(f.temperature)° Fahrenheit")
|
||||
如前所述,你可以在构造器中为存储型属性设置初始值。同样,你也可以在属性声明时为其设置默认值。
|
||||
|
||||
>注意:
|
||||
如果一个属性总是使用同一个初始值,可以为其设置一个默认值。无论定义默认值还是在构造器中赋值,最终它们实现的效果是一样的,只不过默认值将属性的初始化和属性的声明结合的更紧密。使用默认值能让你的构造器更简洁、更清晰,且能通过默认值自动推导出属性的类型;同时,它也能让你充分利用默认构造器、构造器继承(后续章节将讲到)等特性。
|
||||
如果一个属性总是使用相同的初始值,那么为其设置一个默认值比每次都在构造器中赋值要好。两种方法的效果是一样的,只不过使用默认值让属性的初始化和声明结合的更紧密。使用默认值能让你的构造器更简洁、更清晰,且能通过默认值自动推导出属性的类型;同时,它也能让你充分利用默认构造器、构造器继承等特性(后续章节将讲到)。
|
||||
|
||||
你可以使用更简单的方式在定义结构体`Fahrenheit`时为属性`temperature`设置默认值:
|
||||
|
||||
@ -80,17 +80,17 @@ struct Fahrenheit {
|
||||
<a name="customizing_initialization"></a>
|
||||
## 自定义构造过程
|
||||
|
||||
你可以通过输入参数和可选属性类型来定义构造过程,也可以在构造过程中修改常量属性。这些都将在后面章节中提到。
|
||||
你可以通过输入参数和可选属性类型来自定义构造过程,也可以在构造过程中修改常量属性。这些都将在后面章节中提到。
|
||||
|
||||
### 构造参数
|
||||
|
||||
你可以在定义构造器时提供构造参数,为其提供自定义构造所需值的类型和名字。构造器参数的功能和语法跟函数和方法参数相同。
|
||||
自定义`构造过程`时,可以在定义中提供构造参数,指定所需值的类型和名字。构造参数的功能和语法跟函数和方法的参数相同。
|
||||
|
||||
下面例子中定义了一个包含摄氏度温度的结构体`Celsius`。它定义了两个不同的构造器:`init(fromFahrenheit:)`和`init(fromKelvin:)`,二者分别通过接受不同刻度表示的温度值来创建新的实例:
|
||||
|
||||
```swift
|
||||
struct Celsius {
|
||||
var temperatureInCelsius: Double = 0.0
|
||||
var temperatureInCelsius: Double
|
||||
init(fromFahrenheit fahrenheit: Double) {
|
||||
temperatureInCelsius = (fahrenheit - 32.0) / 1.8
|
||||
}
|
||||
@ -199,12 +199,12 @@ cheeseQuestion.response = "Yes, I do like cheese."
|
||||
<a name="assigning_constant_properties_during_initialization"></a>
|
||||
### 构造过程中常量属性的修改
|
||||
|
||||
只要在构造过程结束前常量的值能确定,你可以在构造过程中的任意时间点修改常量属性的值。
|
||||
你可以在构造过程中的任意时间点修改常量属性的值,只要在构造过程结束时是一个确定的值。一旦常量属性被赋值,它将永远不可更改。
|
||||
|
||||
>注意:
|
||||
对某个类实例来说,它的常量属性只能在定义它的类的构造过程中修改;不能在子类中修改。
|
||||
对于类的实例来说,它的常量属性只能在定义它的类的构造过程中修改;不能在子类中修改。
|
||||
|
||||
你可以修改上面的`SurveyQuestion`示例,用常量属性替代变量属性`text`,指明问题内容`text`在其创建之后不会再被修改。尽管`text`属性现在是常量,我们仍然可以在其类的构造器中设置它的值:
|
||||
你可以修改上面的`SurveyQuestion`示例,用常量属性替代变量属性`text`,表示问题内容`text`在`SurveyQuestion`的实例被创建之后不会再被修改。尽管`text`属性现在是常量,我们仍然可以在其类的构造器中设置它的值:
|
||||
|
||||
```swift
|
||||
class SurveyQuestion {
|
||||
@ -226,7 +226,7 @@ beetsQuestion.response = "I also like beets. (But not with cheese.)"
|
||||
<a name="default_initializers"></a>
|
||||
## 默认构造器
|
||||
|
||||
Swift 将为所有属性已提供默认值的且自身没有定义任何构造器的结构体或基类,提供一个默认的构造器。这个默认构造器将简单的创建一个所有属性值都设置为默认值的实例。
|
||||
如果结构体和类的所有属性都有默认值,同时没有自定义的构造器,那么 Swift 会给这些结构体和类创建一个默认构造器。这个默认构造器将简单的创建一个所有属性值都设置为默认值的实例。
|
||||
|
||||
下面例子中创建了一个类`ShoppingListItem`,它封装了购物清单中的某一项的属性:名字(`name`)、数量(`quantity`)和购买状态 `purchase state`。
|
||||
|
||||
@ -635,7 +635,7 @@ let sixEggs = RecipeIngredient(name: "Eggs", quantity: 6)
|
||||
class ShoppingListItem: RecipeIngredient {
|
||||
var purchased = false
|
||||
var description: String {
|
||||
var output = "\(quantity) x \(name.lowercaseString)"
|
||||
var output = "\(quantity) x \(name)"
|
||||
output += purchased ? " ✔" : " ✘"
|
||||
return output
|
||||
}
|
||||
@ -674,7 +674,7 @@ for item in breakfastList {
|
||||
<a name="failable_initializers"></a>
|
||||
## 可失败构造器
|
||||
|
||||
如果一个类,结构体或枚举类型的对象,在构造自身的过程中有可能失败,则为其定义一个可失败构造器,是非常有必要的。这里所指的“失败”是指,如给构造器传入无效的参数值,或缺少某种所需的外部资源,又或是不满足某种必要的条件等。
|
||||
如果一个类、结构体或枚举类型的对象,在构造自身的过程中有可能失败,则为其定义一个可失败构造器,是非常有用的。这里所指的“失败”是指,如给构造器传入无效的参数值,或缺少某种所需的外部资源,又或是不满足某种必要的条件等。
|
||||
|
||||
为了妥善处理这种构造过程中可能会失败的情况。你可以在一个类,结构体或是枚举类型的定义中,添加一个或多个可失败构造器。其语法为在`init`关键字后面加添问号`(init?)`。
|
||||
|
||||
@ -723,11 +723,11 @@ if anonymousCreature == nil {
|
||||
```
|
||||
|
||||
> 注意:
|
||||
空字符串(`""`)和一个值为`nil`的可选类型的字符串是两个完全不同的概念。上例中的空字符串(`""`)其实是一个有效的,非可选类型的字符串。这里我们只所以让`Animal`的可失败构造器,构建对象失败,只是因为对于`Animal`这个类的`species`属性来说,它更适合有一个具体的值,而不是空字符串。
|
||||
空字符串(如`""`,而不是`"Giraffe"`)和一个值为`nil`的可选类型的字符串是两个完全不同的概念。上例中的空字符串(`""`)其实是一个有效的,非可选类型的字符串。这里我们只所以让`Animal`的可失败构造器,构建对象失败,只是因为对于`Animal`这个类的`species`属性来说,它更适合有一个具体的值,而不是空字符串。
|
||||
|
||||
###枚举类型的可失败构造器
|
||||
|
||||
你可以通过构造一个带一个或多个参数的可失败构造器来获取枚举类型中特定的枚举成员。还能在参数不满足你所期望的条件时,导致构造失败。
|
||||
你可以通过构造一个带一个或多个参数的可失败构造器来获取枚举类型中特定的枚举成员。还能在参数不满足枚举成员期望的条件时,构造失败。
|
||||
|
||||
下例中,定义了一个名为TemperatureUnit的枚举类型。其中包含了三个可能的枚举成员(`Kelvin`,`Celsius`,和 `Fahrenheit`)和一个被用来找到`Character`值所对应的枚举成员的可失败构造器:
|
||||
|
||||
@ -791,9 +791,11 @@ if unknownUnit == nil {
|
||||
|
||||
###类的可失败构造器
|
||||
|
||||
值类型(如结构体或枚举类型)的可失败构造器,对何时何地触发构造失败这个行为没有任何的限制。比如在前面的例子中,结构体`Animal`的可失败构造器触发失败的行为,甚至发生在`species`属性的值被初始化以前。而对类而言,就没有那么幸运了。类的可失败构造器只能在所有的类属性被初始化后和所有类之间的构造器之间的代理调用发生完后触发失败行为。
|
||||
值类型(如结构体或枚举类型)的可失败构造器,对何时何地触发构造失败这个行为没有任何的限制。比如在前面的例子中,结构体`Animal`的可失败构造器触发失败的行为,甚至发生在`species`属性的值被初始化以前。
|
||||
|
||||
下例子中,定义了一个名为`Product`的类,其内部结构和结构体`Animal`很相似,内部也有一个名为`name`的`String`类型的属性。由于该属性的值同样不能为空字符串,所以我们加入了可失败构造器来确保该类满足上述条件。但由于`Product`类不是一个结构体,所以当想要在该类中添加可失败构造器触发失败条件时,必须确保`name`属性被初始化。因此我们把`name`属性的`String`类型做了一点点小小的修改,把其改为隐式解析可选类型(`String!`),来确保可失败构造器触发失败条件时,所有类属性都被初始化了。因为所有可选类型都有一个默认的初始值`nil`。因此最后`Product`类可写为:
|
||||
而对类而言,就没有那么幸运了。类的可失败构造器只能在所有的类属性被初始化后和所有类之间的构造器之间的代理调用发生完后触发失败行为。
|
||||
|
||||
下面例子展示了如何使用隐式解析可选类型来实现这个类的可失败构造器的要求:
|
||||
|
||||
```swift
|
||||
class Product {
|
||||
@ -804,8 +806,13 @@ class Product {
|
||||
}
|
||||
}
|
||||
```
|
||||
上面定义的`Product`类,其内部结构和之前`Animal`结构体很相似。`Product`类有一个不能为空字符串的`name`常量属性。为了强制满足这个要求,`Product`类使用了可失败构造器来确保这个属性的值在构造器成功时不为空。
|
||||
|
||||
因为`name`属性是一个常量,所以一旦`Product`类构造成功,`name`属性肯定有一个非`nil`的值。因此完全可以放心大胆的直接访问`Product`类的`name`属性,而不用考虑去检查`name`属性是否有值。
|
||||
毕竟,`Product`是一个类而不是结构体,也就不能和`Animal`一样了。`Product`类的所有可失败构造器必须在自己失败前给`name`属性一个初始值。
|
||||
|
||||
上面的例子中,`Product`类的`name`属性被定义为隐式解析可选字符串类型(`String!`)。因为它是一个可选类型,所以在构造过程里的赋值前,`name`属性有个默认值`nil`。用默认值`nil`意味着`Product`类的所有属性都有一个合法的初始值。因而,在构造器中给`name`属性赋一个特定的值前,可失败构造器能够在传入一个空字符串时触发构造过程的失败。
|
||||
|
||||
因为`name`属性是一个常量,所以一旦`Product`类构造成功,`name`属性肯定有一个非`nil`的值。即使它被定义为隐式解析可选类型,也完全可以放心大胆地直接访问,而不用考虑`name`属性是否有值。
|
||||
|
||||
```swift
|
||||
if let bowTie = Product(name: "bow tie") {
|
||||
@ -897,7 +904,7 @@ class Document {
|
||||
}
|
||||
```
|
||||
|
||||
下面这个例子,定义了一个名为`AutomaticallyNamedDocument`的`Document`类的子类。这个子类重写了基类的两个指定构造器。确保了不论在何种情况下`name`属性总是有一个非空字符串`[Untitled]`的值。
|
||||
下面这个例子,定义了一个`Document`类的子类`AutomaticallyNamedDocument`。这个子类重写了父类的两个指定构造器,确保不论是通过没有 name 参数的构造器,还是通过传一个空字符串给`init(name:)`构造器,生成的实例中的`name`属性总有初始值`"[Untitled]"`。
|
||||
|
||||
```swift
|
||||
class AutomaticallyNamedDocument: Document {
|
||||
@ -916,15 +923,26 @@ class AutomaticallyNamedDocument: Document {
|
||||
}
|
||||
```
|
||||
|
||||
`AutomaticallyNamedDocument`用一个非可失败构造器`init(name:)`,重写了基类的可失败构造器`init?(name:)`。因为子类用不同的方法处理了`name`属性的值为一个空字符串的这种情况。所以子类将不再需要一个可失败的构造器。
|
||||
`AutomaticallyNamedDocument`用一个非可失败构造器`init(name:)`,重写了父类的可失败构造器`init?(name:)`。因为子类用不同的方法处理了`name`属性的值为一个空字符串的这种情况。所以子类将不再需要一个可失败的构造器,用一个非可失败版本代替了父类的版本。
|
||||
|
||||
你可以在构造器中调用父类的可失败构造器强制解包,以实现子类的非可失败构造器。比如,下面的`UntitledDocument `子类总有值为`"[Untitled]"`的 name 属性,它在构造过程中用了父类的可失败的构造器`init(name:)`。
|
||||
|
||||
```swift
|
||||
class UntitledDocument: Document {
|
||||
override init() {
|
||||
super.init(name: "[Untitled]")!
|
||||
}
|
||||
}
|
||||
```
|
||||
在这个例子中,如果在调用父类的构造器`init(name:)`时传给 name 的是空字符串,那么强制解绑操作会造成运行时错误。不过,因为这里是通过字符串常量来调用它,所以并不会发生运行时错误。
|
||||
|
||||
###可失败构造器 init!
|
||||
|
||||
通常来说我们通过在`init`关键字后添加问号的方式来定义一个可失败构造器,但你也可以使用通过在`init`后面添加惊叹号的方式来定义一个可失败构造器`(init!)`,该可失败构造器将会构建一个特定类型的隐式解析可选类型的对象。
|
||||
通常来说我们通过在`init`关键字后添加问号的方式(`init?`)来定义一个可失败构造器,但你也可以使用通过在`init`后面添加惊叹号的方式来定义一个可失败构造器`(init!)`,该可失败构造器将会构建一个特定类型的隐式解析可选类型的对象。
|
||||
|
||||
你可以在 `init? `构造器中代理调用 `init!`构造器,反之亦然。
|
||||
你也可以用 `init?`重写 `init!`,反之亦然。
|
||||
你还可以用 `init`代理调用`init!`,但这会触发一个断言:是否 `init!` 构造器会触发构造失败?
|
||||
你还可以用 `init`代理调用`init!`,但这会触发一个断言: `init!` 构造器是否会触发构造失败?
|
||||
|
||||
<a name="required_initializers"></a>
|
||||
##必要构造器
|
||||
@ -938,7 +956,7 @@ class SomeClass {
|
||||
}
|
||||
}
|
||||
```
|
||||
当子类重写基类的必要构造器时,必须在子类的构造器前同样添加`required`修饰符以确保当其它类继承该子类时,该构造器同为必要构造器。在重写基类的必要构造器时,不需要添加`override`修饰符:
|
||||
在子类重写父类的必要构造器时,必须在子类的构造器前也添加`required`修饰符,这是为了保证继承链上子类的构造器也是必要构造器。在重写父类的必要构造器时,不需要添加`override`修饰符:
|
||||
|
||||
```swift
|
||||
class SomeSubclass: SomeClass {
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
- [闭包引起的循环强引用](#strong_reference_cycles_for_closures)
|
||||
- [解决闭包引起的循环强引用](#resolving_strong_reference_cycles_for_closures)
|
||||
|
||||
Swift 使用自动引用计数(ARC)机制来跟踪和管理你的应用程序的内存。通常情况下,Swift 的内存管理机制会一直起着作用,你无须自己来考虑内存的管理。ARC 会在类的实例不再被使用时,自动释放其占用的内存。
|
||||
Swift 使用自动引用计数(ARC)机制来跟踪和管理你的应用程序的内存。通常情况下,Swift 内存管理机制会一直起作用,你无须自己来考虑内存的管理。ARC 会在类的实例不再被使用时,自动释放其占用的内存。
|
||||
|
||||
然而,在少数情况下,ARC 为了能帮助你管理内存,需要更多的关于你的代码之间关系的信息。本章描述了这些情况,并且为你示范怎样启用 ARC 来管理你的应用程序的内存。
|
||||
|
||||
@ -261,6 +261,13 @@ unit4A = nil
|
||||
|
||||
上面的两段代码展示了变量`john`和`unit4A`在被赋值为`nil`后,`Person`实例和`Apartment`实例的析构函数都打印出“销毁”的信息。这证明了引用循环被打破了。
|
||||
|
||||
<!--
|
||||
NOTE
|
||||
In systems that use garbage collection, weak pointers are sometimes used to implement a simple caching mechanism because objects with no strong references are deallocated only when memory pressure triggers garbage collection. However, with ARC, values are deallocated as soon as their last strong reference is removed, making weak references unsuitable for such a purpose.
|
||||
-->
|
||||
>注意:
|
||||
在使用垃圾收集的系统里,弱指针有时用来实现简单的缓冲机制,因为没有强引用的对象只会在内存压力触发垃圾收集时才被销毁。但是在 ARC 中,一旦值的最后一个强引用被删除,就会被立即销毁,这导致弱引用并不适合上面的用途。
|
||||
|
||||
<a name="2"></a>
|
||||
### 无主引用
|
||||
|
||||
@ -442,6 +449,20 @@ class HTMLElement {
|
||||
|
||||
可以像实例方法那样去命名、使用`asHTML`属性。然而,由于`asHTML`是闭包而不是实例方法,如果你想改变特定元素的 HTML 处理的话,可以用自定义的闭包来取代默认值。
|
||||
|
||||
<!--
|
||||
For example, the asHTML property could be set to a closure that defaults to some text if the text property is nil, in order to prevent the representation from returning an empty HTML tag:
|
||||
-->
|
||||
例如,可以将一个闭包赋值给`asHTML`属性,这个闭包能在文本属性是 nil 时用默认文本,这是为了避免返回一个空的 `HTML` 标签:
|
||||
```swift
|
||||
let heading = HTMLElement(name: "h1")
|
||||
let defaultText = "some default text"
|
||||
heading.asHTML = {
|
||||
return "<\(heading.name)>\(heading.text ?? defaultText)</\(heading.name)>"
|
||||
}
|
||||
print(heading.asHTML())
|
||||
// prints "<h1>some default text</h1>"
|
||||
```
|
||||
|
||||
> 注意:
|
||||
`asHTML`声明为`lazy`属性,因为只有当元素确实需要处理为HTML输出的字符串时,才需要使用`asHTML`。也就是说,在默认的闭包中可以使用`self`,因为只有当初始化完成以及`self`确实存在后,才能访问`lazy`属性。
|
||||
|
||||
@ -480,8 +501,8 @@ paragraph = nil
|
||||
|
||||
在定义闭包时同时定义捕获列表作为闭包的一部分,通过这种方式可以解决闭包和类实例之间的循环强引用。捕获列表定义了闭包体内捕获一个或者多个引用类型的规则。跟解决两个类实例间的循环强引用一样,声明每个捕获的引用为弱引用或无主引用,而不是强引用。应当根据代码关系来决定使用弱引用还是无主引用。
|
||||
|
||||
>注意:
|
||||
Swift 有如下要求:只要在闭包内使用`self`的成员,就要用`self.someProperty`或者`self.someMethod`(而不只是`someProperty`或`someMethod`)。这提醒你可能会一不小心就捕获了`self`。
|
||||
>注意:
|
||||
Swift 有如下要求:只要在闭包内使用`self`的成员,就要用`self.someProperty`或者`self.someMethod()`(而不只是`someProperty`或`someMethod()`)。这提醒你可能会一不小心就捕获了`self`。
|
||||
|
||||
###定义捕获列表
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
> 校对:[dabing1022](https://github.com/dabing1022)
|
||||
|
||||
> 2.0
|
||||
> 翻译+校对:[futantan](https://github.com/futantan)
|
||||
> 翻译+校对:[futantan](https://github.com/futantan),[小铁匠Linus](https://github.com/kevin833752)
|
||||
|
||||
本页包含内容:
|
||||
|
||||
@ -839,7 +839,7 @@ for _ in 1...5 {
|
||||
|
||||
使用扩展协议的方式可以为遵循者提供方法或属性的实现。通过这种方式,可以让你无需在每个遵循者中都实现一次,无需使用全局函数,你可以通过扩展协议的方式进行定义。
|
||||
|
||||
例如,可以扩展`RandomNumberGenerator`协议,让其提供`randomBool()`方法。该方法使用协议中要求的`random()`方法来实现:
|
||||
例如,可以扩展`RandomNumberGenerator`协议,让其提供`randomBool()`方法。该方法使用`random()`方法返回一个随机的`Bool`值:
|
||||
|
||||
```swift
|
||||
extension RandomNumberGenerator {
|
||||
@ -866,12 +866,12 @@ print("And here's a random Boolean: \(generator.randomBool())")
|
||||
> 注意
|
||||
> 通过扩展协议提供的协议实现和可选协议规定有区别。虽然协议遵循者无需自己实现,通过扩展提供的默认实现,可以不是用可选链调用。
|
||||
|
||||
例如,`PrettyTextRepresentable`协议,继承了`TextRepresentable`协议,可以为其提供一个默认的`asPrettyText()`方法来简化返回值
|
||||
例如,`PrettyTextRepresentable`协议,继承自`TextRepresentable`协议,可以为其提供一个默认的`prettyTextualDescription`属性,来简化访问`textualDescription`属性。
|
||||
|
||||
```swift
|
||||
extension PrettyTextRepresentable {
|
||||
func asPrettyText() -> String {
|
||||
return asText()
|
||||
var prettyTextualDescription: String {
|
||||
return textualDescription
|
||||
}
|
||||
}
|
||||
```
|
||||
@ -884,15 +884,16 @@ extension PrettyTextRepresentable {
|
||||
|
||||
```swift
|
||||
extension CollectionType where Generator.Element : TextRepresentable {
|
||||
func asList() -> String {
|
||||
return "(" + ", ".join(map({$0.asText()})) + ")"
|
||||
var textualDescription: String {
|
||||
let itemsAsText = self.map { $0.textualDescription }
|
||||
return "[" + itemsAsText.joinWithSeparator(", ") + "]"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`asList()`方法将每个元素以`asText()`的方式表示,最后以逗号分隔链接起来。
|
||||
`textualDescription`属性将每个元素的文本描述以逗号分隔的方式连接起来。
|
||||
|
||||
现在我们来看`Hamster`,它遵循`TextRepresentable`:
|
||||
现在我们来看`Hamster`,它遵循`TextRepresentable`协议:
|
||||
|
||||
```swift
|
||||
let murrayTheHamster = Hamster(name: "Murray")
|
||||
@ -901,10 +902,10 @@ let mauriceTheHamster = Hamster(name: "Maurice")
|
||||
let hamsters = [murrayTheHamster, morganTheHamster, mauriceTheHamster]
|
||||
```
|
||||
|
||||
因为`Array`遵循`CollectionType`协议,数组的元素又遵循`TextRepresentable`协议,所以数组可以使用`asList()`方法得到数组内容的文本表示:
|
||||
因为`Array`遵循`CollectionType`协议,数组的元素又遵循`TextRepresentable`协议,所以数组可以使用`textualDescription`属性得到数组内容的文本表示:
|
||||
|
||||
```swift
|
||||
print(hamsters.asList())
|
||||
print(hamsters.textualDescription)
|
||||
// 输出 "(A hamster named Murray, A hamster named Morgan, A hamster named Maurice)"
|
||||
```
|
||||
|
||||
|
||||
@ -7,7 +7,8 @@
|
||||
> 校对:[numbbbbb](https://github.com/numbbbbb), [stanzhai](https://github.com/stanzhai)
|
||||
|
||||
> 2.0
|
||||
> 翻译+校对:[Lenhoon](https://github.com/Lenhoon)
|
||||
> 翻译+校对:[Lenhoon](https://github.com/Lenhoon),
|
||||
> [BridgeQ](https://github.com/WXGBridgeQ)
|
||||
|
||||
本页包含内容:
|
||||
|
||||
@ -473,11 +474,11 @@ plusOne(10)
|
||||
|
||||
在程序里使用*枚举声明(enumeration)*来引入一个枚举类型。
|
||||
|
||||
枚举声明有两种基本的形式,使用关键字`enum`来声明。枚举声明体使用从零开始的变量——叫做*枚举事件(enumeration cases)*,和任意数量的声明,包括计算型属性,实例方法,类型方法,构造器,类型别名,甚至其他枚举,结构体,和类。枚举声明不能包含析构器或者协议声明。
|
||||
枚举声明有两种基本的形式,使用关键字`enum`来声明。枚举声明体使用从零开始的变量——叫做*枚举用例(enumeration cases)*,和任意数量的声明,包括计算型属性,实例方法,类型方法,构造器,类型别名,甚至其他枚举,结构体,和类。枚举声明不能包含析构器或者协议声明。
|
||||
|
||||
枚举类型可以采用任何数量的协议,但是这些协议不能从类,结构体和其他的枚举继承。
|
||||
|
||||
不像类或者结构体。枚举类型并不提供隐式的初始构造器,所有构造器必须显式的声明。构造器可以委托枚举中的其他构造器,但是构造过程仅当构造器将一个枚事件指定给`self`才全部完成。
|
||||
不像类或者结构体。枚举类型并不提供隐式的初始构造器,所有构造器必须显式的声明。构造器可以委托枚举中的其他构造器,但是构造过程仅当构造器将一个枚举用例指定给`self`才全部完成。
|
||||
|
||||
和结构体类似但是和类不同,枚举是值类型:枚举实例在赋予变量或常量时,或者被函数调用时被复制。
|
||||
更多关于值类型的信息,参见结构体和枚举都是[值类型(Structures and Enumerations Are Value Types)](TODO)一节。
|
||||
@ -485,9 +486,9 @@ plusOne(10)
|
||||
可以扩展枚举类型,正如在[扩展声明(Extension Declaration)](TODO)中讨论的一样。
|
||||
|
||||
<a name="enumerations_with_cases_of_any_type"></a>
|
||||
###任意事件类型的枚举
|
||||
###任意用例类型的枚举
|
||||
|
||||
如下的形式声明了一个包含任意类型枚举时间的枚举变量
|
||||
如下的形式声明了一个包含任意类型枚举用例的枚举变量
|
||||
|
||||
> enum `enumeration name`: `adopted protocols`{
|
||||
> case `enumeration case 1`
|
||||
@ -496,36 +497,53 @@ plusOne(10)
|
||||
|
||||
这种形式的枚举声明在其他语言中有时被叫做*可识别联合(discrinminated)*。
|
||||
|
||||
这种形式中,每一个事件块由关键字`case`开始,后面紧接着一个或多个以逗号分隔的枚举事件。每一个事件名必须是独一无二的。每一个事件也可以指定它所存储的指定类型的值,这些类型在*关联值类型(associated values types)*的元组里被指定,立即书写在事件
|
||||
名后。获得更多关于关联值类型的信息和例子,请查看[关联值(Associated Values)](TODO)一节。
|
||||
这种形式中,每一个用例块由关键字`case`开始,后面紧接着一个或多个以逗号分隔的枚举用例。每一个用例名必须是独一无二的。每一个用例也可以指定它所存储的指定类型的值,这些类型在*关联值类型(associated values types)*的元组里被指定,立即书写在用例名后。
|
||||
|
||||
枚举有一个递归结构,就是说,枚举有着枚举类型自身实例的关联值的事件。然而,枚举类型的实例有值语义,意味着它们在内存中有着固定的位置。为了支持递归,编译器必需插入一个间接层。
|
||||
枚举用例也可以指定函数作为其存储的值,从而通过特定的关联值创建一个枚举实例。和真正的函数一样,你可以获取一个枚举用例的引用,然后在后续代码中调用它。
|
||||
|
||||
为间接使用特殊的枚举事件,使用`indirect`声明修饰符标记。
|
||||
```swift
|
||||
enum Number {
|
||||
case Integer(Int)
|
||||
case Real(Double)
|
||||
}
|
||||
let f = Number.Integer
|
||||
// f is a function of type (Int) -> Number
|
||||
// f 是一个传入 Int 返回 Number 类型的函数
|
||||
|
||||
// Apply f to create an array of Number instances with integer values
|
||||
// 利用函数 f 把一个整数数组转成 Number 数组
|
||||
let evenInts: [Number] = [0, 2, 4, 6].map(f)
|
||||
```
|
||||
|
||||
获得更多关于关联值类型的信息和例子,请查看[关联值(Associated Values)](TODO)一节。
|
||||
|
||||
枚举有一个递归结构,就是说,枚举有着枚举类型自身实例的关联值的用例。然而,枚举类型的实例有值语义,意味着它们在内存中有着固定的位置。为了支持递归,编译器必需插入一个间接层。
|
||||
|
||||
为间接使用特殊的枚举用例,使用`indirect`声明修饰符标记。
|
||||
|
||||
> enum Tree<T> {
|
||||
> case Empty
|
||||
> indirect case Node(value: T, left: Tree, right:Tree)
|
||||
> }
|
||||
|
||||
为了间接的使用一个枚举的所有事件,使用`indirect`修饰符标记整个枚举-当枚举有许多事件且每个事件都需要使用`indirect`修饰符标记的时候这将非常便利。
|
||||
为了间接的使用一个枚举的所有用例,使用`indirect`修饰符标记整个枚举-当枚举有许多用例且每个用例都需要使用`indirect`修饰符标记的时候这将非常便利。
|
||||
|
||||
一个被`indirect`修饰符标记的枚举事件必需有一个关联值。一个使用`indirect`修饰符标记的枚举包含有着关联值的事件和没有关联值的事件的混合。就是说,它不能包含任何也使用`indirect`修饰符标记的事件。
|
||||
一个被`indirect`修饰符标记的枚举用例必需有一个关联值。一个使用`indirect`修饰符标记的枚举包含有着关联值的用例和没有关联值的用例的混合。就是说,它不能包含任何也使用`indirect`修饰符标记的用例。
|
||||
|
||||
|
||||
<a name="enumerations_with_cases_of_a_raw-value_type"></a>
|
||||
###使用原始值类型事件的枚举(Enumerations with Cases of a Raw-Value Type)
|
||||
###使用原始值类型用例的枚举(Enumerations with Cases of a Raw-Value Type)
|
||||
|
||||
以下的形式声明了一个包含相同基础类型的枚举事件的枚举:
|
||||
以下的形式声明了一个包含相同基础类型的枚举用例的枚举:
|
||||
|
||||
> enum `enumeration name`: `raw value type`, `adopted protocols`{
|
||||
> case `enumeration case 1` = `raw value 1`
|
||||
> case `enumeration case 2` = `raw value 2`
|
||||
> }
|
||||
|
||||
在这种形式中,每一个事件块由`case`关键字开始,后面紧接着一个或多个以逗号分隔的枚举事件。和第一种形式的枚举事件不同,这种形式的枚举事件包含一个同类型的基础值,叫做*原始值(raw value)*。这些值的类型在*原始值类型(raw-value type)*中被指定,必须表示一个整数,浮点数,字符串,或者一个字符。特别是*原始值类型(raw-value type)*必需遵守`Equatable`类型的协议和下列形式中的一种字面量构造协议(literal-convertible protocols):整型字面量有`IntergerLiteralConvertible`,浮点行字面量有`FloatingPointLiteralConvertible`,包含任意数量字符的字符串型字面量有`StringLiteralConvertible`,仅包含一个单一字符的字符串型字面量有`ExtendedGraphemeClusterLiteralConvertible`。每一个事件必须有唯一的名字,必须有一个唯一的初始值。
|
||||
在这种形式中,每一个用例块由`case`关键字开始,后面紧接着一个或多个以逗号分隔的枚举用例。和第一种形式的枚举用例不同,这种形式的枚举用例包含一个同类型的基础值,叫做*原始值(raw value)*。这些值的类型在*原始值类型(raw-value type)*中被指定,必须表示一个整数,浮点数,字符串,或者一个字符。特别是*原始值类型(raw-value type)*必需遵守`Equatable`类型的协议和下列形式中的一种字面量构造协议(literal-convertible protocols):整型字面量有`IntergerLiteralConvertible`,浮点行字面量有`FloatingPointLiteralConvertible`,包含任意数量字符的字符串型字面量有`StringLiteralConvertible`,仅包含一个单一字符的字符串型字面量有`ExtendedGraphemeClusterLiteralConvertible`。每一个用例必须有唯一的名字,必须有一个唯一的初始值。
|
||||
|
||||
如果初始值类型被指定为`Int`,则不必为事件显式的指定值,它们会隐式的被标为值`0,1,2`等。每一个没有被赋值的`Int`类型时间会隐式的赋予一个初始值,它们是自动递增的。
|
||||
如果初始值类型被指定为`Int`,则不必为用例显式的指定值,它们会隐式的被标为值`0,1,2`等。每一个没有被赋值的`Int`类型时间会隐式的赋予一个初始值,它们是自动递增的。
|
||||
|
||||
```Swift
|
||||
num ExampleEnum: Int {
|
||||
@ -535,7 +553,7 @@ num ExampleEnum: Int {
|
||||
|
||||
在上面的例子中,`ExampleEnum.A`的值是`0`,`ExampleEnum.B`的值是`1`。因为`ExampleEnum.C`的值被显式的设定为`5`,因此`ExampleEnum.D`的值会自动增长为`6`。
|
||||
|
||||
如果原始值类型被指定为`String`类型,你不用明确的为事件指定值,每一个没有指定的事件会隐式地用与事件名字相同的字符串指定。
|
||||
如果原始值类型被指定为`String`类型,你不用明确的为用例指定值,每一个没有指定的用例会隐式地用与用例名字相同的字符串指定。
|
||||
|
||||
> enum WeekendDay: String {
|
||||
> case Saturday, Sunday
|
||||
@ -543,14 +561,14 @@ num ExampleEnum: Int {
|
||||
|
||||
在上面这个例子中,`WeekendDay.Saturday`的原始值是`"Saturday"`,`WeekendDay.Sunday`的原始值是`"Sunday"`。
|
||||
|
||||
拥有多种事件的原始值类型的枚举含蓄地遵循定义在Swift标准库中的`RawRepresentable`协议。所以,它们拥有一个原始值(`rawValue`)属性和一个有着`init?(rawValue: RawValue)`签名的可失败构造器(a failable initializer)。可以使用原始值属性去取的枚举事件的原始值,就像在`ExampleEnum.B.rawValue`中一样。如果有一个事件符合,也可以使用原始值去找到一个符合的事件,通过调用枚举的可失败构造器,如`ExampleEnum(rawValue: 5)`,这个可失败构造器返回一个可选的事件。想得到更多的信息和关于原始值类型查看更多信息和获取初始值类型事件的信息,参阅初始值[原始值(Raw Values)](TODO)。
|
||||
拥有多种用例的原始值类型的枚举含蓄地遵循定义在Swift标准库中的`RawRepresentable`协议。所以,它们拥有一个原始值(`rawValue`)属性和一个有着`init?(rawValue: RawValue)`签名的可失败构造器(a failable initializer)。可以使用原始值属性去取的枚举用例的原始值,就像在`ExampleEnum.B.rawValue`中一样。如果有一个用例符合,也可以使用原始值去找到一个符合的用例,通过调用枚举的可失败构造器,如`ExampleEnum(rawValue: 5)`,这个可失败构造器返回一个可选的用例。想得到更多的信息和关于原始值类型查看更多信息和获取初始值类型用例的信息,参阅初始值[原始值(Raw Values)](TODO)。
|
||||
|
||||
<a name="accessing_enumeration_cases"></a>
|
||||
###获得枚举事件
|
||||
###获得枚举用例
|
||||
|
||||
使用点(.)来引用枚举类型的事件,如`EnumerationType.EnumerationCase`。当枚举类型可以上下文推断出时,可以省略它(.仍然需要),参照枚举语法[(Enumeration Syntax)](TODO)和[显式成员表达(Implicit Member Expression)](TODO)。
|
||||
使用点(.)来引用枚举类型的用例,如`EnumerationType.EnumerationCase`。当枚举类型可以上下文推断出时,可以省略它(.仍然需要),参照枚举语法[(Enumeration Syntax)](TODO)和[显式成员表达(Implicit Member Expression)](TODO)。
|
||||
|
||||
使用`switch`语句来检验枚举事件的值,正如使用[switch语句匹配枚举值(Matching Enumeration Values with a Switch Statement)](TODO)一节描述的那样。枚举类型是模式匹配(pattern-matched)的,和其相反的是`switch`语句case块中枚举事件匹配,在[枚举事件类型(Enumeration Case Pattern)](TODO)中有描述。
|
||||
使用`switch`语句来检验枚举用例的值,正如使用[switch语句匹配枚举值(Matching Enumeration Values with a Switch Statement)](TODO)一节描述的那样。枚举类型是模式匹配(pattern-matched)的,和其相反的是`switch`语句case块中枚举用例匹配,在[枚举用例类型(Enumeration Case Pattern)](TODO)中有描述。
|
||||
|
||||
<a name="grammer_of_an_enumeration_declaration"></a>
|
||||
> 枚举声明语法
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
> 校对:[numbbbbb](https://github.com/numbbbbb), [stanzhai](https://github.com/stanzhai)
|
||||
|
||||
> 2.0
|
||||
> 翻译+校对:[KYawn](https://github.com/KYawn)
|
||||
> 翻译+校对:[KYawn](https://github.com/KYawn),[小铁匠Linus](https://github.com/kevin833752)
|
||||
|
||||
本页内容包括:
|
||||
|
||||
@ -71,6 +71,9 @@
|
||||
protocol MyProtocol {
|
||||
// protocol definition
|
||||
}
|
||||
```
|
||||
|
||||
```swift
|
||||
// Subsequent release renames MyProtocol
|
||||
protocol MyRenamedProtocol {
|
||||
// protocol definition
|
||||
@ -80,14 +83,14 @@ protocol MyRenamedProtocol {
|
||||
typealias MyProtocol = MyRenamedProtocol
|
||||
```
|
||||
|
||||
|
||||
你可以在一个单独的声明上使用多个`available`特性,以详细说明该声明在不同平台上的有效性。编译器只有在当前的目标平台和`available`特性中指定的平台匹配时,才会使用`available`特性
|
||||
你可以在一个单独的声明上使用多个`available`特性,以详细说明该声明在不同平台上的有效性。编译器只有在当前的目标平台和`available`特性中指定的平台匹配时,才会使用`available`特性。
|
||||
|
||||
如果`available`特性除了平台名称参数外,只指定了一个`introduced `参数,那么可以使用以下简写语法代替:
|
||||
|
||||
@available(`platform name` `version number`, *)
|
||||
|
||||
`available`特性的简写语法可以简明地表达出多个平台的可用性。尽管这两种形式在功能上是相同的,但请尽可能地使用简明语法形式。
|
||||
|
||||
```swift
|
||||
@available(iOS 8.0, OSX 10.10, *)
|
||||
class MyClass {
|
||||
@ -107,7 +110,7 @@ class MyClass {
|
||||
|
||||
```swift
|
||||
@objc
|
||||
class ExampleClass {
|
||||
class ExampleClass: NSObject {
|
||||
var enabled: Bool {
|
||||
@objc(isEnabled) get {
|
||||
// Return the appropriate value
|
||||
@ -138,7 +141,7 @@ class ExampleClass {
|
||||
|
||||
在类上使用该特性表示该类是应用程序委托类,使用该特性与调用`NSApplicationMain(_:_:)`函数并且把该类的名字作为委托类的名字传递给函数的效果相同。
|
||||
|
||||
如果你不想使用这个特性,可以提供一个`main.swift`文件,并且提供一个`main`函数去调用`NSApplicationMain(_:_:)`函数。比如,如果你的应用程序使用一个派生于`NSApplication`的自定义子类作为主要类,你可以调用`NSApplicationMain`函数而不是使用该特性。
|
||||
如果你不想使用这个特性,可以提供一个`main.swift`文件,并且提供一个`main()`函数去调用`NSApplicationMain(_:_:)`函数。比如,如果你的应用程序使用一个派生于`NSApplication`的自定义子类作为主要类,你可以调用`NSApplicationMain`函数而不是使用该特性。
|
||||
|
||||
`NSCopying`
|
||||
|
||||
@ -148,7 +151,7 @@ class ExampleClass {
|
||||
|
||||
`NSManaged`
|
||||
|
||||
该特性用于修饰`NSManagedObject`子类中的存储型变量属性,表明属性的存储和实现由Core Data在运行时基于相关实体描述动态提供。
|
||||
该特性用于修饰`NSManagedObject`子类中的实例方法或存储型变量属性,表明属性的存储和实现由Core Data在运行时基于相关实体描述动态提供。对于标记了`NSManaged`特性的属性,Core Data也会在运行时提供存储。
|
||||
|
||||
`testable`
|
||||
|
||||
@ -164,16 +167,15 @@ class ExampleClass {
|
||||
|
||||
该特性应用于方法或函数声明,当方法或函数被调用,但其结果未被使用时,该特性会让编译器会产生警告。
|
||||
|
||||
你可以使用这个特性提供一个警告信息,这个警告信息是关于不正确地使用未变异的方法的,这个方法也有一个对应的变异方法。
|
||||
你可以使用这个特性提供一个警告信息,这个警告信息是关于不正确地使用未变异的方法,这个方法也有一个对应的变异方法。
|
||||
|
||||
`warn_unused_result`有下面两个可选的参数。
|
||||
`warn_unused_result`特性会有选择地采用下面两个参数之一。
|
||||
|
||||
- `message`参数用来提供警告信息,并在因当方法或函数被调用,但其结果未被使用时,显示警告信息。格式如下:
|
||||
- `message`参数用来提供警告信息。在当方法或函数被调用,但其结果未被使用时,会显示警告信息。格式如下:
|
||||
<p>`message=message`<p>这里的`message`由一个字符串文字构成。
|
||||
|
||||
- `mutable_variant`参数用于提供变异方法的名称,如果未变异方法以一个可变的值被调用而且其结果并未被使用时,应该使用此变异方法。格式如下(方法名有字符串构成):<p>`mutable_variant=method name`<p>
|
||||
|
||||
比如,Swift标准库提供了变异方法`sortInPlace()`和未变异方法`sort()`集合,它们的元素生成器符合`Comparable`协议。如果你调用了`sort()`方法,而没有使用它的结果,很有可能,你打算使用变异方法`sortInPlace()`替代。
|
||||
比如,Swift标准库同时提供了变异方法`sortInPlace()`和未变异方法`sort()`集合,它们的元素生成器符合`Comparable`协议。如果你调用了`sort()`方法,而没有使用它的结果,其实很有可能,你是打算使用变异方法`sortInPlace()`。
|
||||
|
||||
### Interface Builder使用的声明特性
|
||||
|
||||
@ -190,7 +192,7 @@ Interface Builder特性是Interface Builder用来与Xcode同步的声明特性
|
||||
|
||||
该特性用于函数的类型,它指出函数调用的约定。
|
||||
|
||||
`convention`特性有下面几个可选的参数。
|
||||
`convention`特性总是与下面的参数之一一起出现。
|
||||
|
||||
- `swift`参数用于表明一个Swift函数引用。这是Swift中标准的函数值调用约定。
|
||||
|
||||
|
||||
@ -6,7 +6,8 @@
|
||||
> 校对:[numbbbbb](https://github.com/numbbbbb), [stanzhai](https://github.com/stanzhai)
|
||||
|
||||
> 2.0
|
||||
> 翻译+校对:[ray16897188](https://github.com/ray16897188)
|
||||
> 翻译+校对:[ray16897188](https://github.com/ray16897188),
|
||||
> [BridgeQ](https://github.com/WXGBridgeQ)
|
||||
|
||||
本页内容包括:
|
||||
|
||||
@ -132,7 +133,7 @@ let (a): Int = 2 // a: Int = 2
|
||||
<a name="optional_pattern"></a>
|
||||
## 可选模式(Optional Pattern)
|
||||
|
||||
可选模式与封装在一个`Optional(T)`或者一个`ExplicitlyUnwrappedOptional(T)`枚举中的`Some(T)`用例相匹配。可选模式由一个标识符模式和紧随其后的一个问号组成,在某些情况下表现为枚举用例模式。
|
||||
可选模式与封装在一个`Optional(Wrapped)`或者一个`ExplicitlyUnwrappedOptional(Wrapped)`枚举中的`Some(Wrapped)`用例相匹配。可选模式由一个标识符模式和紧随其后的一个问号组成,在某些情况下表现为枚举用例模式。
|
||||
|
||||
由于可选模式是`optional`和`ImplicitlyUnwrappedOptional`枚举用例模式的语法糖(syntactic sugar),下面的2种写法是一样的:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user