From da6d08cd6e18c2bcd15cfe582d065a6fffb0c8ce Mon Sep 17 00:00:00 2001 From: BqLin Date: Sun, 15 Apr 2018 11:02:03 +0800 Subject: [PATCH] =?UTF-8?q?markdown=20=E6=A0=BC=E5=BC=8F=E5=92=8C=E6=A0=87?= =?UTF-8?q?=E7=82=B9=E7=AC=A6=E5=8F=B7=E7=9A=84=E4=B8=80=E4=BA=9B=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3=20(#780)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 修正全角逗号、句号的使用 * 修正逗号使用 * 修正一处代码空格错误 * 修正斜体范围,引用的空格使用 * 修正示例代码错误 * 修正标点,修正示例代码 * 修正标点 * 修正标点 * 添加 Swift 3.1 的更新 * 修改 Swift 3.0.1 位置 * 添加 Swift 4.0.3 更新 * 添加 Swift 4.1 更新 * 修正示例代码 * 修正 markdown 引用语法,优化翻译语句 * 修正示例代码 * 修正标点使用,优化翻译语句 * 修正示例代码 * 修正示例代码 * 优化翻译语句,修正示例代码语法 * 更新示例代码以符合 Swift 4.1 * 优化 markdown 引用格式的使用 * 优化 markdown 行内代码块使用,代码块与正文使用空格分隔 * 人工校验 markdown 行内代码块使用 * 中英文空格分隔 * 移除行末空格 * 人工校验 markdown 行内代码块使用 * 修正 markdown 无序列表使用 * 统一 markdown 行间代码块的使用 * 人工修正顿号与句号的使用 * 人工修改双引号的使用 * 行内代码块使用“`代码块`”格式 --- source/chapter1/03_a_swift_tour.md | 1 + source/chapter2/01_The_Basics.md | 8 +++--- source/chapter2/03_Strings_and_Characters.md | 1 + source/chapter2/04_Collection_Types.md | 7 +++--- source/chapter2/05_Control_Flow.md | 13 +++++----- source/chapter2/06_Functions.md | 2 +- source/chapter2/08_Enumerations.md | 2 +- source/chapter2/14_Initialization.md | 6 ++--- source/chapter2/16_Optional_Chaining.md | 2 +- source/chapter2/18_Type_Casting.md | 1 + source/chapter2/20_Extensions.md | 1 + source/chapter2/21_Protocols.md | 3 ++- source/chapter2/22_Generics.md | 1 - source/chapter2/25_Access_Control.md | 4 +-- source/chapter2/26_Advanced_Operators.md | 2 ++ source/chapter3/03_Types.md | 6 +++-- source/chapter3/04_Expressions.md | 1 + source/chapter3/06_Declarations.md | 8 ++++++ source/chapter3/07_Attributes.md | 2 ++ source/chapter4/01_Access_Control.md | 1 + source/chapter4/02_Type_Custom.md | 16 +++++++++--- .../04_Interacting_with_C_Pointers.md | 6 +++++ source/chapter4/07_Optional_Case_Study.md | 25 +++++++++---------- 23 files changed, 77 insertions(+), 42 deletions(-) diff --git a/source/chapter1/03_a_swift_tour.md b/source/chapter1/03_a_swift_tour.md index 9012334d..00c21fe3 100755 --- a/source/chapter1/03_a_swift_tour.md +++ b/source/chapter1/03_a_swift_tour.md @@ -86,6 +86,7 @@ let label = "The width is" let width = 94 let widthLabel = label + String(width) ``` + > 练习 > > 删除最后一行中的 `String`,错误提示是什么? diff --git a/source/chapter2/01_The_Basics.md b/source/chapter2/01_The_Basics.md index 715e27c7..7f21f560 100755 --- a/source/chapter2/01_The_Basics.md +++ b/source/chapter2/01_The_Basics.md @@ -58,7 +58,7 @@ Swift 是一门开发 iOS, macOS, watchOS 和 tvOS 应用的新语言。然而,如果你有 C 或者 Objective-C 开发经验的话,你会发现 Swift 的很多内容都是你熟悉的。 -Swift 包含了 C 和 Objective-C 上所有基础数据类型,`Int` 表示整型值; `Double` 和 `Float` 表示浮点型值; `Bool` 是布尔型值;`String` 是文本型数据。 Swift 还提供了三个基本的集合类型,`Array` ,`Set` 和 `Dictionary` ,详见[集合类型](./04_Collection_Types.html)。 +Swift 包含了 C 和 Objective-C 上所有基础数据类型,`Int` 表示整型值; `Double` 和 `Float` 表示浮点型值; `Bool` 是布尔型值;`String` 是文本型数据。 Swift 还提供了三个基本的集合类型,`Array`、`Set` 和 `Dictionary` ,详见[集合类型](./04_Collection_Types.html)。 就像 C 语言一样,Swift 使用变量来进行存储并通过变量名来关联值。在 Swift 中,广泛的使用着值不可变的变量,它们就是常量,而且比 C 语言的常量更强大。在 Swift 中,如果你要处理的值不需要改变,那使用常量可以让你的代码更加安全并且更清晰地表达你的意图。 @@ -233,7 +233,7 @@ let cat = "🐱"; print(cat) 整数就是没有小数部分的数字,比如 `42` 和 `-23` 。整数可以是 `有符号`(正、负、零)或者 `无符号`(正、零)。 -Swift 提供了8,16,32和64位的有符号和无符号整数类型。这些整数类型和 C 语言的命名方式很像,比如8位无符号整数类型是 `UInt8`,32位有符号整数类型是 `Int32` 。就像 Swift 的其他类型一样,整数类型采用大写命名法。 +Swift 提供了8、16、32和64位的有符号和无符号整数类型。这些整数类型和 C 语言的命名方式很像,比如8位无符号整数类型是 `UInt8`,32位有符号整数类型是 `Int32` 。就像 Swift 的其他类型一样,整数类型采用大写命名法。 ### 整数范围 @@ -272,7 +272,7 @@ Swift 也提供了一个特殊的无符号类型 `UInt`,长度与当前平台 ## 浮点数 -浮点数是有小数部分的数字,比如 `3.14159` ,`0.1` 和 `-273.15`。 +浮点数是有小数部分的数字,比如 `3.14159`、`0.1` 和 `-273.15`。 浮点类型比整数类型表示的范围更大,可以存储比 `Int` 类型更大或者更小的数字。Swift 提供了两种有符号浮点数类型: @@ -820,7 +820,7 @@ assert(age >= 0, "A person's age cannot be less than zero") ```swift assert(age >= 0) -``` +``` 如果代码已经检查了条件,你可以使用 `assertionFailure(_:file:line:)` 函数来表明断言失败了,例如: diff --git a/source/chapter2/03_Strings_and_Characters.md b/source/chapter2/03_Strings_and_Characters.md index 547add3b..896c31ba 100755 --- a/source/chapter2/03_Strings_and_Characters.md +++ b/source/chapter2/03_Strings_and_Characters.md @@ -227,6 +227,7 @@ for character in "Dog!🐶" { ```swift let exclamationMark: Character = "!" ``` + 字符串可以通过传递一个值类型为 `Character` 的数组作为自变量来初始化: ```swift diff --git a/source/chapter2/04_Collection_Types.md b/source/chapter2/04_Collection_Types.md index e1631210..b4156103 100755 --- a/source/chapter2/04_Collection_Types.md +++ b/source/chapter2/04_Collection_Types.md @@ -194,7 +194,7 @@ shoppingList[0] = "Six eggs" // 其中的第一项现在是 "Six eggs" 而不是 "Eggs" ``` -还可以利用下标来一次改变一系列数据值,即使新数据和原有数据的数量是不一样的。下面的例子把 `"Chocolate Spread"`,`"Cheese"`,和 `"Butter"` 替换为 `"Bananas"` 和 `"Apples"`: +还可以利用下标来一次改变一系列数据值,即使新数据和原有数据的数量是不一样的。下面的例子把 `"Chocolate Spread"`、`"Cheese"` 和 `"Butter"` 替换为 `"Bananas"` 和 `"Apples"`: ```swift shoppingList[4...6] = ["Bananas", "Apples"] @@ -223,6 +223,7 @@ let mapleSyrup = shoppingList.remove(at: 0) // shoppingList 现在只有6项,而且不包括 Maple Syrup // mapleSyrup 常量的值等于被移除数据项的值 "Maple Syrup" ``` + > 注意 > > 如果我们试着对索引越界的数据进行检索或者设置新值的操作,会引发一个运行期错误。我们可以使用索引值和数组的 `count` 属性进行比较来在使用某个索引之前先检验是否有效。除了当 `count` 等于 0 时(说明这是个空数组),最大索引值一直是 `count - 1`,因为数组都是零起索引。 @@ -295,7 +296,7 @@ Swift 的所有基本类型(比如 `String`,`Int`,`Double` 和 `Bool`)默认都 > > 你可以使用你自定义的类型作为集合的值的类型或者是字典的键的类型,但你需要使你的自定义类型符合 Swift 标准库中的 `Hashable` 协议。符合 `Hashable` 协议的类型需要提供一个类型为 `Int` 的可读属性 `hashValue`。由类型的 `hashValue` 属性返回的值不需要在同一程序的不同执行周期或者不同程序之间保持相同。 > -> 因为 `Hashable` 协议符合 `Equatable` 协议,所以遵循该协议的类型也必须提供一个"是否相等"运算符(`==`)的实现。这个 `Equatable` 协议要求任何符合 `==` 实现的实例间都是一种相等的关系。也就是说,对于 `a,b,c` 三个值来说,`==` 的实现必须满足下面三种情况: +> 因为 `Hashable` 协议符合 `Equatable` 协议,所以遵循该协议的类型也必须提供一个“是否相等”运算符(`==`)的实现。这个 `Equatable` 协议要求任何符合 `==` 实现的实例间都是一种相等的关系。也就是说,对于 `a,b,c` 三个值来说,`==` 的实现必须满足下面三种情况: > * `a == a`(自反性) > * `a == b` 意味着 `b == a`(对称性) @@ -608,7 +609,7 @@ airports["LHR"] = "London" ```swift airports["LHR"] = "London Heathrow" -// "LHR"对应的值 被改为 "London Heathrow +// “LHR”对应的值被改为“London Heathrow” ``` 作为另一种下标方法,字典的 `updateValue(_:forKey:)` 方法可以设置或者更新特定键对应的值。就像上面所示的下标示例,`updateValue(_:forKey:)` 方法在这个键不存在对应值的时候会设置新值或者在存在时更新已存在的值。和上面的下标方法不同的,`updateValue(_:forKey:)` 这个方法返回更新值之前的原值。这样使得我们可以检查更新是否成功。 diff --git a/source/chapter2/05_Control_Flow.md b/source/chapter2/05_Control_Flow.md index a8148844..5bd11a5a 100755 --- a/source/chapter2/05_Control_Flow.md +++ b/source/chapter2/05_Control_Flow.md @@ -110,7 +110,7 @@ print("\(base) to the power of \(power) is \(answer)") 在某些情况下,你可能不想使用闭区间,包括两个端点。想象一下,你在一个手表上绘制分钟的刻度线。总共 `60` 个刻度,从 `0` 分开始。使用半开区间运算符(`..<`)来表示一个左闭右开的区间。有关区间的更多信息,请参阅[区间运算符](./02_Basic_Operators.html#range_operators)。 -``` +```swift let minutes = 60 for tickMark in 0.. 注意 @@ -563,7 +565,6 @@ default: } // 输出 "On an axis, 9 from the origin" - ``` 上面的 case 有两个模式:`(let distance, 0)` 匹配了在 x 轴上的值,`(0, let distance)` 匹配了在 y 轴上的值。两个模式都绑定了 `distance`,并且 `distance` 在两种模式下,都是整型——这意味着分支体内的代码,只要 case 匹配,都可以获取到 `distance` 值 diff --git a/source/chapter2/06_Functions.md b/source/chapter2/06_Functions.md index 16a8e385..0a377c73 100755 --- a/source/chapter2/06_Functions.md +++ b/source/chapter2/06_Functions.md @@ -34,7 +34,7 @@ - [函数类型](#Function_Types) - [嵌套函数](#Nested_Functions) -*函数*是一段完成特定任务的独立代码片段。你可以通过给函数命名来标识某个函数的功能,这个名字可以被用来在需要的时候"调用"这个函数来完成它的任务。 +*函数*是一段完成特定任务的独立代码片段。你可以通过给函数命名来标识某个函数的功能,这个名字可以被用来在需要的时候“调用”这个函数来完成它的任务。 Swift 统一的函数语法非常的灵活,可以用来表示任何函数,包括从最简单的没有参数名字的 C 风格函数,到复杂的带局部和外部参数名的 Objective-C 风格函数。参数可以提供默认值,以简化函数调用。参数也可以既当做传入参数,也当做传出参数,也就是说,一旦函数执行结束,传入的参数值将被修改。 diff --git a/source/chapter2/08_Enumerations.md b/source/chapter2/08_Enumerations.md index 48ee20b4..7af86a22 100755 --- a/source/chapter2/08_Enumerations.md +++ b/source/chapter2/08_Enumerations.md @@ -223,7 +223,7 @@ enum ASCIIControlCharacter: Character { 枚举类型 `ASCIIControlCharacter` 的原始值类型被定义为 `Character`,并设置了一些比较常见的 ASCII 控制字符。`Character` 的描述详见[字符串和字符](./03_Strings_and_Characters.html)部分。 -原始值可以是字符串,字符,或者任意整型值或浮点型值。每个原始值在枚举声明中必须是唯一的。 +原始值可以是字符串、字符,或者任意整型值或浮点型值。每个原始值在枚举声明中必须是唯一的。 > 注意 > diff --git a/source/chapter2/14_Initialization.md b/source/chapter2/14_Initialization.md index 85d5a63f..329a251e 100755 --- a/source/chapter2/14_Initialization.md +++ b/source/chapter2/14_Initialization.md @@ -743,7 +743,7 @@ for item in breakfastList { 例如,实现针对数字类型转换的可失败构造器。确保数字类型之间的转换能保持精确的值,使用这个 `init(exactly:)` 构造器。如果类型转换不能保持值不变,则这个构造器构造失败。 -``` +```swift let wholeNumber: Double = 12345.0 let pi = 3.14159 @@ -808,7 +808,7 @@ if anonymousCreature == nil { 你可以通过一个带一个或多个参数的可失败构造器来获取枚举类型中特定的枚举成员。如果提供的参数无法匹配任何枚举成员,则构造失败。 -下例中,定义了一个名为 `TemperatureUnit` 的枚举类型。其中包含了三个可能的枚举成员(`Kelvin`,`Celsius`,和 `Fahrenheit`),以及一个根据 `Character` 值找出所对应的枚举成员的可失败构造器: +下例中,定义了一个名为 `TemperatureUnit` 的枚举类型。其中包含了三个可能的枚举成员(`Kelvin`、`Celsius` 和 `Fahrenheit`),以及一个根据 `Character` 值找出所对应的枚举成员的可失败构造器: ```swift enum TemperatureUnit { @@ -990,7 +990,7 @@ class UntitledDocument: Document { } } ``` - + 在这个例子中,如果在调用父类的可失败构造器 `init?(name:)` 时传入的是空字符串,那么强制解包操作会引发运行时错误。不过,因为这里是通过非空的字符串常量来调用它,所以并不会发生运行时错误。 diff --git a/source/chapter2/16_Optional_Chaining.md b/source/chapter2/16_Optional_Chaining.md index c777a3c0..a705678f 100755 --- a/source/chapter2/16_Optional_Chaining.md +++ b/source/chapter2/16_Optional_Chaining.md @@ -388,7 +388,7 @@ if let johnsStreet = john.residence?.address?.street { 上面的例子展示了如何在一个可选值上通过可选链式调用来获取它的属性值。我们还可以在一个可选值上通过可选链式调用来调用方法,并且可以根据需要继续在方法的可选返回值上进行可选链式调用。 在下面的例子中,通过可选链式调用来调用 `Address` 的 `buildingIdentifier()` 方法。这个方法返回 `String?` 类型的值。如上所述,通过可选链式调用来调用该方法,最终的返回值依旧会是 `String?` 类型: - + ```swift if let buildingIdentifier = john.residence?.address?.buildingIdentifier() { print("John's building identifier is \(buildingIdentifier).") diff --git a/source/chapter2/18_Type_Casting.md b/source/chapter2/18_Type_Casting.md index 468ee904..7a38539a 100644 --- a/source/chapter2/18_Type_Casting.md +++ b/source/chapter2/18_Type_Casting.md @@ -230,6 +230,7 @@ for thing in things { > `Any` 类型可以表示所有类型的值,包括可选类型。Swift 会在你用 `Any` 类型来表示一个可选值的时候,给你一个警告。如果你确实想使用 `Any` 类型来承载可选值,你可以使用 `as` 操作符显式转换为 `Any`,如下所示: > > + ```swift let optionalNumber: Int? = 3 things.append(optionalNumber) // 警告 diff --git a/source/chapter2/20_Extensions.md b/source/chapter2/20_Extensions.md index 370f8846..5ba6af35 100644 --- a/source/chapter2/20_Extensions.md +++ b/source/chapter2/20_Extensions.md @@ -137,6 +137,7 @@ struct Rect { var size = Size() } ``` + 因为结构体 `Rect` 未提供定制的构造器,因此它会获得一个逐一成员构造器。又因为它为所有存储型属性提供了默认值,它又会获得一个默认构造器。详情请参阅[默认构造器](./14_Initialization.html#default_initializers)。这些构造器可以用于构造新的 `Rect` 实例: ```swift diff --git a/source/chapter2/21_Protocols.md b/source/chapter2/21_Protocols.md index 990ed235..088f5e7e 100644 --- a/source/chapter2/21_Protocols.md +++ b/source/chapter2/21_Protocols.md @@ -705,7 +705,7 @@ beginConcert(in: seattle) // Prints "Hello, Seattle!" ``` -`beginConcert(in:)` 方法接受一个类型为 `Location & Named` 的参数,这意味着"任何 Location 的子类,并且遵循 Named 协议"。例如,City 就满足这样的条件。 +`beginConcert(in:)` 方法接受一个类型为 `Location & Named` 的参数,这意味着“任何 Location 的子类,并且遵循 Named 协议”。例如,City 就满足这样的条件。 将 birthdayPerson 传入 `beginConcert(in:)` 函数是不合法的,因为 Person 不是一个 Location 的子类。就像,如果你新建一个类继承与 Location,但是没有遵循 Named 协议,你用这个类的实例去调用 `beginConcert(in:)` 函数也是不合法的。 @@ -967,6 +967,7 @@ extension Collection where Element: Equatable { let equalNumbers = [100, 100, 100, 100, 100] let differentNumbers = [100, 100, 200, 100, 200] ``` + 由于数组遵循 `Collection` 而且整数遵循 `Equatable`,`equalNumbers` 和 `differentNumbers` 都可以使用 `allEqual()` 方法。 diff --git a/source/chapter2/22_Generics.md b/source/chapter2/22_Generics.md index df807f97..20563d22 100644 --- a/source/chapter2/22_Generics.md +++ b/source/chapter2/22_Generics.md @@ -103,7 +103,6 @@ func swapTwoValues(_ a: inout T, _ b: inout T) { a = b b = temporaryA } - ``` `swapTwoValues(_:_:)` 的函数主体和 `swapTwoInts(_:_:)` 函数是一样的,它们只在第一行有点不同,如下所示: diff --git a/source/chapter2/25_Access_Control.md b/source/chapter2/25_Access_Control.md index 69c57d5d..18d88b33 100644 --- a/source/chapter2/25_Access_Control.md +++ b/source/chapter2/25_Access_Control.md @@ -174,7 +174,7 @@ private class SomePrivateClass { // 显式 private 类 func somePrivateMethod() {} // 隐式 private 类成员 } -``` +```swift ### 元组类型 @@ -434,7 +434,7 @@ extension SomeStruct: SomeProtocol { ## 类型别名 -你定义的任何类型别名都会被当作不同的类型,以便于进行访问控制。类型别名的访问级别不可高于其表示的类型的访问级别。例如,`private` 级别的类型别名可以作为 `private`,`file-private`,`internal`,`public` 或者 `open` 类型的别名,但是 `public` 级别的类型别名只能作为 `public` 类型的别名,不能作为 `internal`,`file-private`,或 `private` 类型的别名。 +你定义的任何类型别名都会被当作不同的类型,以便于进行访问控制。类型别名的访问级别不可高于其表示的类型的访问级别。例如,`private` 级别的类型别名可以作为 `private`、`file-private`、`internal`、`public` 或者 `open` 类型的别名,但是 `public` 级别的类型别名只能作为 `public` 类型的别名,不能作为 `internal`、`file-private` 或 `private` 类型的别名。 > 注意 > diff --git a/source/chapter2/26_Advanced_Operators.md b/source/chapter2/26_Advanced_Operators.md index 738c8f19..4007946d 100644 --- a/source/chapter2/26_Advanced_Operators.md +++ b/source/chapter2/26_Advanced_Operators.md @@ -380,6 +380,7 @@ let negative = -positive let alsoPositive = -negative // alsoPositive 是一个值为 (3.0, 4.0) 的 Vector2D 实例 ``` + ### 复合赋值运算符 @@ -433,6 +434,7 @@ if twoThree == anotherTwoThree { } // 打印 “These two vectors are equivalent.” ``` + Swift 为以下自定义类型提等价运算符供合成实现: - 只拥有遵循 `Equatable` 协议存储属性的结构体; diff --git a/source/chapter3/03_Types.md b/source/chapter3/03_Types.md index 683fb7cb..b01ad3eb 100644 --- a/source/chapter3/03_Types.md +++ b/source/chapter3/03_Types.md @@ -64,6 +64,7 @@ Swift 语言存在两种类型:命名型类型和复合型类型。命名型 let someTuple: (Double, Double) = (3.14159, 2.71828) func someFunction(a: Int) { /* ... */ } ``` + 在第一个例子中,表达式 `someTuple` 的类型被指定为 `(Double, Double)`。在第二个例子中,函数 `someFunction` 的参数 `a` 的类型被指定为 `Int`。 类型注解可以在类型之前包含一个类型特性的可选列表。 @@ -166,7 +167,7 @@ f = functionWithDifferentNumberOfArguments // 错误 由于变量标签不是函数类型的一部分,你可以在写函数类型的时候省略它们。 -``` +```swift var operation: (lhs: Int, rhs: Int) -> Int // 错误 var operation: (_ lhs: Int, _ rhs: Int) -> Int // 正确 var operation: (Int, Int) -> Int // 正确 @@ -180,7 +181,7 @@ var operation: (Int, Int) -> Int // 正确 ### 对非逃逸闭包的限制 非逃逸闭包函数不能作为参数传递到另一个非逃逸闭包函数的参数。这样的限制可以让 Swift 在编译时就完成更多的内存访问冲突检查, 而不是在运行时。举个例子: -``` +```swift let external: (Any) -> Void = { _ in () } func takesTwoFunctions(first: (Any) -> Void, second: (Any) -> Void) { first(first) // 错误 @@ -193,6 +194,7 @@ func takesTwoFunctions(first: (Any) -> Void, second: (Any) -> Void) { external(first) // 正确 } ``` + 在上面代码里,`takesTwoFunctions(first:second:)` 的两个参数都是函数。 它们都没有标记为 `@escaping`, 因此它们都是非逃逸的。 上述例子里的被标记为“错误”的四个函数调用会产生编译错误。因为第一个和第二个参数是非逃逸函数,它们不能够被当作变量被传递到另一个非闭包函数参数。与此相反, 标记“正确”的两个函数不回产生编译错误。这些函数调用不会违反限制, 因为 `外部(external)` 不是 `takesTwoFunctions(first:second:)` 里的一个参数。 diff --git a/source/chapter3/04_Expressions.md b/source/chapter3/04_Expressions.md index 39619894..6d63f762 100644 --- a/source/chapter3/04_Expressions.md +++ b/source/chapter3/04_Expressions.md @@ -587,6 +587,7 @@ class SomeClass: NSObject { let selectorForMethod = #selector(SomeClass.doSomething(_:)) let selectorForPropertyGetter = #selector(getter: SomeClass.property) ``` + 当为属性的 getter 创建选择器时,属性名可以是变量属性或者常量属性的引用。但是当为属性的 setter 创建选择器时,属性名只可以是对变量属性的引用。 方法名称可以包含圆括号来进行分组,并使用 as 操作符来区分具有相同方法名但类型不同的方法,例如: diff --git a/source/chapter3/06_Declarations.md b/source/chapter3/06_Declarations.md index 7983b3b6..f621654c 100755 --- a/source/chapter3/06_Declarations.md +++ b/source/chapter3/06_Declarations.md @@ -102,6 +102,7 @@ Swift 的源文件中的顶级代码 (top-level code) 由零个或多个语句 语句 } ``` + 代码块中的“语句”包括声明、表达式和各种其他类型的语句,它们按照在源码中的出现顺序被依次执行。 > 代码块语法 @@ -332,6 +333,7 @@ typealias 类型别名 = 现存类型 当声明一个类型的别名后,可以在程序的任何地方使用“别名”来代替现有类型。现有类型可以是具有命名的类型或者混合类型。类型别名不产生新的类型,它只是使用别名来引用现有类型。 类型别名声明可以通过泛型参数来给一个现有泛型类型提供名称。类型别名为现有类型的一部分或者全部泛型参数提供具体类型。例如: + ```swift typealias StringDictionary = Dictionary @@ -339,12 +341,16 @@ typealias StringDictionary = Dictionary var dictionary1: StringDictionary = [:] var dictionary2: Dictionary = [:] ``` + 当一个类型别名带着泛型参数一起被声明时,这些参数的约束必须与现有参数的约束完全匹配。例如: + ```swift typealias DictionaryOfInts = Dictionary ``` + 因为类型别名可以和现有类型相互交换使用,类型别名不可以引入额外的类型约束。 在协议声明中,类型别名可以为那些经常使用的类型提供一个更短更方便的名称,例如: + ```swift protocol Sequence { associatedtype Iterator: IteratorProtocol @@ -355,6 +361,7 @@ func sum(_ sequence: T) -> Int where T.Element == Int { // ... } ``` + 假如没有类型别名,sum 函数将必须引用关联类型通过 T.Iterator.Element 的形式来替代 T.Element。 另请参阅 [协议关联类型声明](#protocol_associated_type_declaration)。 @@ -1096,6 +1103,7 @@ extension 类型名称 where 要求 { 声明语句 } ``` + 扩展声明体可包含零个或多个声明语句。这些声明语句可以包括计算型属性、计算型类型属性、实例方法、类型方法、构造器、下标声明,甚至是类、结构体和枚举声明。扩展声明不能包含析构器、协议声明、存储型属性、属性观察器或其他扩展声明。关于扩展声明的详细讨论,以及各种扩展声明的例子,请参阅 [扩展](../chapter2/21_Extensions.md)。 如果类型为类,结构体,或枚举类型,则扩展声明会扩展相应的类型。如果类型为协议类型,则扩展声明会扩展所有遵守这个协议的类型。在扩展的协议体中声明语句不能使用 `final` 标识符。 diff --git a/source/chapter3/07_Attributes.md b/source/chapter3/07_Attributes.md index 0c8d3591..63a0c91b 100755 --- a/source/chapter3/07_Attributes.md +++ b/source/chapter3/07_Attributes.md @@ -141,6 +141,7 @@ var enabled: Bool { } } ``` + `nonobjc` 该特性用于方法、属性、下标、或构造器的声明,这些声明本可以在 Objective-C 代码中使用,而使用 `nonobjc` 特性则告诉编译器这个声明不能在 Objective-C 代码中使用。 @@ -159,6 +160,7 @@ var enabled: Bool { import AppKit NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv) ``` + `NSCopying` 该特性用于修饰一个类的存储型变量属性。该特性将使属性的设值方法使用传入值的副本进行赋值,这个值由传入值的 `copyWithZone`(\_:) 方法返回。该属性的类型必需符合 `NSCopying` 协议。 diff --git a/source/chapter4/01_Access_Control.md b/source/chapter4/01_Access_Control.md index dbdc6ec9..27b79f82 100644 --- a/source/chapter4/01_Access_Control.md +++ b/source/chapter4/01_Access_Control.md @@ -38,6 +38,7 @@ Private(私有级别)的权限最严格,它可以用来隐藏某些功能 除了可以给整个声明设权限,Swift 还允许大家在需要的时候,把某个属性(property)的取值权限比赋值权限设得更加开放。 #####举个例子: + ```swift public class ListItem { diff --git a/source/chapter4/02_Type_Custom.md b/source/chapter4/02_Type_Custom.md index df2031a3..9ae1c210 100644 --- a/source/chapter4/02_Type_Custom.md +++ b/source/chapter4/02_Type_Custom.md @@ -39,6 +39,7 @@ case ocFalse ####实现默认值 行,我们给了一个漂亮的定义,不过按照传统语言的经验,Bool 值默认情况下是假, 所以我们的 OCBool 也应该如此,我们使用类型扩展技术增加这个默认特性: + ```swift extension OCBool{ init(){ @@ -65,14 +66,17 @@ var result1:OCBool = .ocTrue 正如上述代码所述,我们只能通过类型或者枚举项目赋值,这是组合类型的用法,但是编码的日子里,我们总是希望和 true,false 直接打交道,也就是说,我们希望这么做, 代码示例如下: + ```swift var isSuccess:OCBool = true ``` 如果小伙伴们直接这么用,则会出现如下错误: + ``` /Users/tyrion-OldCoder/Documents/Learning/BoolType/BoolType/main.swift:30:24: Type 'OCBool' does not conform to protocol 'BooleanLiteralConvertible' ``` + 编译器咆哮的原因是,我们的类型没有遵从“布尔字面量转换协议”,接下来修正这个问题, #####代码示例如下: @@ -99,6 +103,7 @@ var isSuccess:OCBool = true - 代码中的第11行是重点,我的类型 OCBool 支持了 BooleanLiteralConvertible 协议,这个协到底是干什么的呢,小伙伴们在 Xcode 代码编辑器,按住 Command 键,然后点击第11行中的 BooleanLiteralConvertible 协议名,则会进入它的定义, #####其定义如下: + ```swift protocol BooleanLiteralConvertible { typealias BooleanLiteralType @@ -119,14 +124,16 @@ protocol BooleanLiteralConvertible { var isSuccess:OCBool = true if isSuccess { - println( "老码请你吃火锅!") + println("老码请你吃火锅!") } ``` 你永远吃不到老码的火锅,因为这里编译器会咆哮: + ``` /Users/tyrion-OldCoder/Documents/Learning/BoolType/BoolType/main.swift:27:4: Type 'OCBool' does not conform to protocol 'LogicValue' ``` + OCBool 现在只能用 bool 类型初始化,而不能直接返回 bool 型,小火把们还记得在《老码说编程之白话 Swift 江湖》中,老码多次提到,妈妈再也不担心我们 if a = 1{}的写法了, 因为等号不支持值返回了, 所以在 if 判断是后面的条件必须有返回值,OCBool 没有,所以编译器哭了。我们解决这个问题。 #####代码示例如下: @@ -164,7 +171,7 @@ extension OCBool: LogicValue{ var isSuccess:OCBool = true if isSuccess { - println( "老码请你吃火锅!") + println("老码请你吃火锅!") } ``` @@ -207,7 +214,7 @@ var mmResult: Bool = true var ocResult:OCBool = OCBool(mmResult) if ocResult { - println( "老码没钱,郭美美请你吃火锅!") + println("老码没钱,郭美美请你吃火锅!") } ``` @@ -218,6 +225,7 @@ Hello, World! 老码没钱,郭美美请你吃火锅! Program ended with exit code: 0 ``` + 漂亮!我们的 OCBool 类型现在支持了所有的逻辑变量初始化。 #####注意: @@ -287,7 +295,7 @@ isHasWife ^ isHasLover isHasWife = !isHasLover if (isHasMoney | isHasHealty) & isHasHealty{ - println( "人生赢家,就像老码一样!") + println("人生赢家,就像老码一样!") }else { println("人生最苦的事事,人死了钱没花了,人生最苦的事是,人活着,钱没了!") diff --git a/source/chapter4/04_Interacting_with_C_Pointers.md b/source/chapter4/04_Interacting_with_C_Pointers.md index affe7230..f2a0ce68 100644 --- a/source/chapter4/04_Interacting_with_C_Pointers.md +++ b/source/chapter4/04_Interacting_with_C_Pointers.md @@ -16,11 +16,14 @@ Objective-C 和 C 的 API 常常会需要用到指针。Swift 中的数据类型 ####用以输入/输出的参数指针 C 和 Objective-C 并不支持多返回值,所以 Cocoa API 中常常将指针作为一种在方法间传递额外数据的方式。Swift 允许指针被当作 `inout` 参数使用,所以你可以用符号 `&` 将对一个变量的引用作为指针参数传递。举例来说:`UIColor` 中的 `getRed(_:green:blue:alpha:)` 方法需要四个 `CGFloat*` 指针来接收颜色的组成信息,我们使用 `&` 来将这些组成信息捕获为本地变量: + ```swift var r: CGFloat = 0, g: CGFloat = 0, b: CGFloat = 0, a: CGFloat = 0 color.getRed(&r, green: &g, blue: &b, alpha: &a) ``` + 另一种常见的情况是 Cocoa 中 `NSError` 的习惯用法。许多方法会使用一个 `NSError**` 参数来储存可能的错误的信息。举例来说:我们用 `NSFileManager` 的 `contentOfDirectoryAtPath(_:error:)` 方法来将目录下的内容列表,并将潜在的错误指向一个 `NSError?` 变量: + ```swift var maybeError: NSError? if let contents = NSFileManager.defaultManager() @@ -30,11 +33,13 @@ if let contents = NSFileManager.defaultManager() // Handle the error } ``` + 为了安全性,Swift 要求被使用 `&` 传递的变量已经初始化。因为无法确定这个方法会不会在写入数据前尝试从指针中读取数据。 ####作为数组使用的参数指针 在 C 语言中,数组和指针的联系十分紧密,而 Swift 允许数组能够作为指针使用,从而与基于数组的 C 语言 API 协同工作更加简单。一个固定的数组可以使用一个常量指针直接传递,一个变化的数组可以用 `&` 运算符将一个非常量指针传递。就和输入/输出参数指针一样。举例来说:我们可以用 Accelerate 框架中的 `vDSP_vadd` 方法让两个数组 `a` 和 `b` 相加,并将结果写入第三个数组 `result`。 + ```swift import Accelerate @@ -50,6 +55,7 @@ vDSP_vadd(a, 1, b, 1, &result, 1, 4) ## 用作字符串参数的指针 C 语言中用 `cont char*` 指针来作为传递字符串的基本方式。Swift 中的 `String` 可以被当作一个无限长度 UTF-8编码的 `const char*` 指针来传递给方法。举例来说:我们可以直接传递一个字符串给一个标准 C 和 POSIX 库方法 + ```swift puts("Hello from libc") let fd = open("/tmp/scratch.txt", O_WRONLY|O_CREAT, 0o666) diff --git a/source/chapter4/07_Optional_Case_Study.md b/source/chapter4/07_Optional_Case_Study.md index cae5e8f7..ff8c9938 100644 --- a/source/chapter4/07_Optional_Case_Study.md +++ b/source/chapter4/07_Optional_Case_Study.md @@ -16,9 +16,9 @@ #### 为 Dictionary 增加 objectsForKeys 函数 -在 Objective-C 中,```NSDictionary```有一个方法```-objectsForKeys:NoFoundMarker:```, 这个方法需要一个```NSArray```数组作为键值参数,然后返回一个包含相关值的数组。文档里写到:"返回数组中的第 N 个值,和输入数组中的第 N 个值相对应",那如果有某个键值在字典里不存在呢?于是就有了```notFoundMarker```作为返回提示。比如第三个键值没有找到,那么在返回数组中第三个值就是这个```notFoundMarker```,而不是字典中的第三个值,但是这个值只是用来提醒原字典中没有找到对应值,但在返回数组中该元素存在,且用```notFoundMarker```作为占位符,因为这个对象不能直接使用,所以在 Foundation 框架中有个专门的类处理这个情况:```NSNull```。 +在 Objective-C 中,`NSDictionary` 有一个方法 `-objectsForKeys:NoFoundMarker:`, 这个方法需要一个 `NSArray` 数组作为键值参数,然后返回一个包含相关值的数组。文档里写到:“返回数组中的第 N 个值,和输入数组中的第 N 个值相对应”,那如果有某个键值在字典里不存在呢?于是就有了 `notFoundMarker` 作为返回提示。比如第三个键值没有找到,那么在返回数组中第三个值就是这个 `notFoundMarker`,而不是字典中的第三个值,但是这个值只是用来提醒原字典中没有找到对应值,但在返回数组中该元素存在,且用 `notFoundMarker` 作为占位符,因为这个对象不能直接使用,所以在 Foundation 框架中有个专门的类处理这个情况:`NSNull`。 -在 Swift 中,```Dictionary```类没有类似```objectsForKeys```的函数,为了说明问题,我们动手加一个,并且使其成为操作字典值的通用方法。我们可以用```extension```来实现: +在 Swift 中,`Dictionary` 类没有类似 `objectsForKeys` 的函数,为了说明问题,我们动手加一个,并且使其成为操作字典值的通用方法。我们可以用 `extension` 来实现: ```swift extension Dictionary{ @@ -28,7 +28,7 @@ extension Dictionary{ } ``` -以上就是我们实现的 Swift 版本,这个和 Objective-C 版本有很大区别。在 Swift 中,因为其强类型的原因限制了返回的结果数组只能包含单一类型的元素,所以我们不能放```NSNull```在字符串数组中,但是,Swift 有更好的选择,我们可以返回一个可选类型数据。我们所有的值都封包在可选类型中,而不是```NSNull```, 我们只用```nil```就可以了。 +以上就是我们实现的 Swift 版本,这个和 Objective-C 版本有很大区别。在 Swift 中,因为其强类型的原因限制了返回的结果数组只能包含单一类型的元素,所以我们不能放 `NSNull` 在字符串数组中,但是,Swift 有更好的选择,我们可以返回一个可选类型数据。我们所有的值都封包在可选类型中,而不是 `NSNull`, 我们只用 `nil` 就可以了。 ```swift extension Dictionary{ @@ -56,7 +56,7 @@ extension Dictionary { } ``` -上述方式实现的功能和最开始的方法实现的功能相同,虽然核心的功能是封装了```map```的调用,这个例子也说明了为什么 Swift 没有提供轻量级的 API 接口,因为小伙伴们简单的调用```map```就可以实现。 +上述方式实现的功能和最开始的方法实现的功能相同,虽然核心的功能是封装了 `map` 的调用,这个例子也说明了为什么 Swift 没有提供轻量级的 API 接口,因为小伙伴们简单的调用 `map` 就可以实现。 接下来,我们实验几个例子: @@ -76,7 +76,7 @@ t = dic.valuesForKeys([]) #### 内嵌可选类型 -现在,如果我们为每一个结果调用```last```方法,看下结果如何? +现在,如果我们为每一个结果调用 `last` 方法,看下结果如何? ```swift var dic: Dictionary = [ "1": 2, "3":3, "4":5 ] @@ -89,20 +89,19 @@ var t = dict.valuesForKeys(["3", "9"]).last var t = dict.valuesForKeys([]).last // 结果为:nil - ``` -小伙伴们立马迷糊了,为什么会出现两层包含的可选类型呢?,特别对第二种情况的```Optional(nil)```,这是什么节奏? +小伙伴们立马迷糊了,为什么会出现两层包含的可选类型呢?,特别对第二种情况的 `Optional(nil)`,这是什么节奏? -我们回过头看看```last```属性的定义: +我们回过头看看 `last` 属性的定义: ```swift var last:T? { get } ``` -很明显```last```属性的类型是数组元素类型的可选类型,这种情况下,因为元素类型是```(String?)```,那么再结合返回的类型,于是其结果就是```String??```了,这就是所谓的嵌套可选类型。但嵌套可选类型本质是什么意思呢? +很明显 `last` 属性的类型是数组元素类型的可选类型,这种情况下,因为元素类型是 `(String?)`,那么再结合返回的类型,于是其结果就是 `String??` 了,这就是所谓的嵌套可选类型。但嵌套可选类型本质是什么意思呢? -如果在 Objective-C 中重新调用上述方法,我们将使用```NSNull```作为占位符,Objective-C 的调用语法如下所示: +如果在 Objective-C 中重新调用上述方法,我们将使用 `NSNull` 作为占位符,Objective-C 的调用语法如下所示: ```swift [dict valuesForKeys:@[@"1", @"4"] notFoundMarker:[NSNull null]].lastObject @@ -113,7 +112,7 @@ var last:T? { get } // nil ``` -不管是 Swift 版本还是 Objective-C 版本,返回值为```nil```都意味数组是空的,所以它就没有最后一个元素。 但是如果返回是```Optional(nil)```或者 Objective-C 中的```NSNull```都表示数组中的最后一个元素存在,但是元素的内容是空的。在 Objective-C 中只能借助```NSNull```作为占位符来达到这个目的,但是 Swift 却可以语言系统类型的角度的实现。 +不管是 Swift 版本还是 Objective-C 版本,返回值为 `nil` 都意味数组是空的,所以它就没有最后一个元素。 但是如果返回是 `Optional(nil)` 或者 Objective-C 中的 `NSNull` 都表示数组中的最后一个元素存在,但是元素的内容是空的。在 Objective-C 中只能借助 `NSNull` 作为占位符来达到这个目的,但是 Swift 却可以语言系统类型的角度的实现。 #### 提供一个默认值 @@ -128,11 +127,11 @@ extension Dictionary { } ``` -``` +```swift dict.valuesForKeys(["1", "5"], notFoundMarker: "Anonymous") ``` -和 Objective-C 相比,其需要占位符来达到占位的目的,但是 Swift 却已经从语言类型系统的层面原生的支持了这种用法,同时提供了丰富的语法功能。这就是 Swift 可选类型的强大之处。同时注意上述例子中用到了空合运算符```??```。 +和 Objective-C 相比,其需要占位符来达到占位的目的,但是 Swift 却已经从语言类型系统的层面原生的支持了这种用法,同时提供了丰富的语法功能。这就是 Swift 可选类型的强大之处。同时注意上述例子中用到了空合运算符 `??`。 ----------------- 本章节不是老码的原创,是老码认真的阅读了苹果的官方博客,自己的练习总结,如果小伙伴们费了吃奶的劲还是看不懂,请找度娘谷歌。还是看不懂?请到老码[官方微博](http://weibo.com/u/5241713117)咆哮。