diff --git a/source/chapter1/chapter1.md b/source/chapter1/chapter1.md index 089600ca..c765d2e2 100755 --- a/source/chapter1/chapter1.md +++ b/source/chapter1/chapter1.md @@ -1,4 +1,3 @@ # 欢迎使用 Swift 在本章中您将了解 Swift 的特性和开发历史,并对 Swift 有一个初步的了解。 - diff --git a/source/chapter2/01_The_Basics.md b/source/chapter2/01_The_Basics.md index 1cce7140..9259d202 100755 --- a/source/chapter2/01_The_Basics.md +++ b/source/chapter2/01_The_Basics.md @@ -19,9 +19,9 @@ > 校对:[CMB](https://github.com/chenmingbiao),版本时间2016-09-13 > > 3.0.1, 2016-11-11,shanks - -> 4.0 -> 校对:[kemchenj](https://kemchenj.github.io) + +> 4.0 +> 校对:[kemchenj](https://kemchenj.github.io) 本页包含内容: @@ -185,6 +185,7 @@ print("The current value of friendlyWelcome is \(friendlyWelcome)") ## 注释 + 请将你的代码中的非执行文本注释成提示或者笔记以方便你将来阅读。Swift 的编译器将会在编译代码时自动忽略掉注释部分。 Swift 中的注释与 C 语言的注释非常相似。单行注释以双正斜杠(`//`)作为起始标记: @@ -212,6 +213,7 @@ Swift 中的注释与 C 语言的注释非常相似。单行注释以双正斜 ## 分号 + 与其他大部分编程语言不同,Swift 并不强制要求你在每条语句的结尾处使用分号(`;`),当然,你也可以按照你自己的习惯添加分号。有一种情况下必须要用分号,即你打算在同一行内写多条独立的语句: ```swift @@ -727,6 +729,7 @@ if let definiteString = assumedString { ## 错误处理 + 你可以使用 *错误处理(error handling)* 来应对程序执行中可能会遇到的错误条件。 相对于可选中运用值的存在与缺失来表达函数的成功与失败,错误处理可以推断失败的原因,并传播至程序的其他部分。 @@ -794,7 +797,7 @@ do { ```swift let age = -3 -assert(age >= 0, "A person's age cannot be less than zero") +assert(age >= 0, "A person's age cannot be less than zero") // 因为 age < 0,所以断言会触发 ``` @@ -833,5 +836,4 @@ precondition(index > 0, "Index must be greater than zero.") > 注意: > 如果你使用unchecked模式(-Ounchecked)编译代码,先决条件将不会进行检查。编译器假设所有的先决条件总是为true(真),他将优化你的代码。然而,`fatalError(_:file:line:)`函数总是中断执行,无论你怎么进行优化设定。 ->你能使用 `fatalError(_:file:line:)`函数在设计原型和早期开发阶段,这个阶段只有方法的声明,但是没有具体实现,你可以在方法体中写上fatalError("Unimplemented")作为具体实现。因为fatalError不会像断言和先决条件那样被优化掉,所以你可以确保当代码执行到一个没有被实现的方法时,程序会被中断。 - +>你能使用 `fatalError(_:file:line:)`函数在设计原型和早期开发阶段,这个阶段只有方法的声明,但是没有具体实现,你可以在方法体中写上fatalError("Unimplemented")作为具体实现。因为fatalError不会像断言和先决条件那样被优化掉,所以你可以确保当代码执行到一个没有被实现的方法时,程序会被中断。 diff --git a/source/chapter2/02_Basic_Operators.md b/source/chapter2/02_Basic_Operators.md index 13dd7322..02a3f06f 100755 --- a/source/chapter2/02_Basic_Operators.md +++ b/source/chapter2/02_Basic_Operators.md @@ -14,9 +14,9 @@ > 2.2 > 翻译+校对:[Cee](https://github.com/Cee) 校对:[SketchK](https://github.com/SketchK),2016-05-11 > 3.0.1,shanks,2016-11-11 - -> 4.0 -> 翻译+校对:[kemchenj](https://kemchenj.github.io) + +> 4.0 +> 翻译+校对:[kemchenj](https://kemchenj.github.io) 本页包含内容: @@ -237,14 +237,14 @@ if name == "world" { (4, "dog") == (4, "dog") // true,因为 4 等于 4,dog 等于 dog ``` -在上面的例子中,你可以看到,在第一行中从左到右的比较行为。因为`1`小于`2`,所以`(1, "zebra")`小于`(2, "apple")`,不管元组剩下的值如何。所以`"zebra"`大于`"apple"`对结果没有任何影响,因为元组的比较结果已经被第一个元素决定了。不过,当元组的第一个元素相同时候,第二个元素将会用作比较-第二行和第三行代码就发生了这样的比较。 +在上面的例子中,你可以看到,在第一行中从左到右的比较行为。因为`1`小于`2`,所以`(1, "zebra")`小于`(2, "apple")`,不管元组剩下的值如何。所以`"zebra"`大于`"apple"`对结果没有任何影响,因为元组的比较结果已经被第一个元素决定了。不过,当元组的第一个元素相同时候,第二个元素将会用作比较-第二行和第三行代码就发生了这样的比较。 -当元组中的元素都可以被比较时,你也可以使用这些运算符来比较它们的大小。例如,像下面展示的代码,你可以比较两个类型为 `(String, Int)` 的元组,因为 `Int` 和 `String` 类型的值可以比较。相反,`Bool` 不能被比较,也意味着存有布尔类型的元组不能被比较。 - -```swift -("blue", -1) < ("purple", 1) // 正常,比较的结果为 true -("blue", false) < ("purple", true) // 错误,因为 < 不能比较布尔类型 -``` +当元组中的元素都可以被比较时,你也可以使用这些运算符来比较它们的大小。例如,像下面展示的代码,你可以比较两个类型为 `(String, Int)` 的元组,因为 `Int` 和 `String` 类型的值可以比较。相反,`Bool` 不能被比较,也意味着存有布尔类型的元组不能被比较。 + +```swift +("blue", -1) < ("purple", 1) // 正常,比较的结果为 true +("blue", false) < ("purple", true) // 错误,因为 < 不能比较布尔类型 +``` >注意: Swift 标准库只能比较七个以内元素的元组比较函数。如果你的元组元素超过七个时,你需要自己实现比较运算符。 @@ -334,6 +334,7 @@ colorNameToUse = userDefinedColorName ?? defaultColorName Swift 提供了几种方便表达一个区间的值的*区间运算符*。 ### 闭区间运算符 + *闭区间运算符*(`a...b`)定义一个包含从 `a` 到 `b`(包括 `a` 和 `b`)的所有值的区间。`a` 的值不能超过 `b`。 ‌ 闭区间运算符在迭代一个区间的所有值时是非常有用的,如在 `for-in` 循环中: @@ -371,44 +372,44 @@ for i in 0.. ## 逻辑运算符(Logical Operators) @@ -511,5 +512,3 @@ if (enteredDoorCode && passedRetinaScan) || hasDoorKey || knowsOverridePassword ``` 这括号使得前两个值被看成整个逻辑表达中独立的一个部分。虽然有括号和没括号的输出结果是一样的,但对于读代码的人来说有括号的代码更清晰。可读性比简洁性更重要,请在可以让你代码变清晰的地方加个括号吧! - - diff --git a/source/chapter2/03_Strings_and_Characters.md b/source/chapter2/03_Strings_and_Characters.md index 8b21488b..49da955c 100755 --- a/source/chapter2/03_Strings_and_Characters.md +++ b/source/chapter2/03_Strings_and_Characters.md @@ -818,5 +818,3 @@ for scalar in dogString.unicodeScalars { // ‼ // 🐶 ``` - - diff --git a/source/chapter2/05_Control_Flow.md b/source/chapter2/05_Control_Flow.md index e56d1578..932f9c59 100755 --- a/source/chapter2/05_Control_Flow.md +++ b/source/chapter2/05_Control_Flow.md @@ -815,4 +815,3 @@ if #available(platform name version, ..., *) { APIs 不可用,语句将不执行 } ``` - diff --git a/source/chapter2/06_Functions.md b/source/chapter2/06_Functions.md index 6d506922..cb46f36d 100755 --- a/source/chapter2/06_Functions.md +++ b/source/chapter2/06_Functions.md @@ -39,12 +39,13 @@ Swift 统一的函数语法非常的灵活,可以用来表示任何函数, ## 函数的定义与调用 + 当你定义一个函数时,你可以定义一个或多个有名字和类型的值,作为函数的输入,称为*参数*,也可以定义某种类型的值作为函数执行结束时的输出,称为*返回类型*。 每个函数有个*函数名*,用来描述函数执行的任务。要使用一个函数时,用函数名来“调用”这个函数,并传给它匹配的输入值(称作 *实参* )。函数的实参必须与函数参数表里参数的顺序一致。 -下面例子中的函数的名字是`greet(person:)`,之所以叫这个名字,是因为这个函数用一个人的名字当做输入,并返回向这个人问候的语句。为了完成这个任务,你需要定义一个输入参数——一个叫做 `person` 的 `String` 值,和一个包含给这个人问候语的 `String` 类型的返回值: +下面例子中的函数的名字是`greet(person:)`,之所以叫这个名字,是因为这个函数用一个人的名字当做输入,并返回向这个人问候的语句。为了完成这个任务,你需要定义一个输入参数——一个叫做 `person` 的 `String` 值,和一个包含给这个人问候语的 `String` 类型的返回值: ```swift @@ -87,6 +88,7 @@ print(greetAgain(person: "Anna")) ## 函数参数与返回值 + 函数参数与返回值在 Swift 中非常的灵活。你可以定义任何类型的函数,包括从只带一个未名参数的简单函数到复杂的带有表达性参数名和不同参数选项的复杂函数。 @@ -168,6 +170,7 @@ printWithoutCounting(string: "hello, world") ### 多重返回值函数 + 你可以用元组(tuple)类型让多个值作为一个复合值从函数中返回。 下例中定义了一个名为 `minMax(array:)` 的函数,作用是在一个 `Int` 类型的数组中找出最小值与最大值。 @@ -499,7 +502,6 @@ let moveNearerToZero = chooseStepFunction(backward: currentValue > 0) 现在,`moveNearerToZero`指向了正确的函数,它可以被用来数到零: - ```swift print("Counting to zero:") // Counting to zero: diff --git a/source/chapter2/07_Closures.md b/source/chapter2/07_Closures.md index 4df68dfe..3ffac397 100755 --- a/source/chapter2/07_Closures.md +++ b/source/chapter2/07_Closures.md @@ -456,4 +456,3 @@ for customerProvider in customerProviders { ``` 在上面的代码中,`collectCustomerProviders(_:)` 函数并没有调用传入的 `customerProvider` 闭包,而是将闭包追加到了 `customerProviders` 数组中。这个数组定义在函数作用域范围外,这意味着数组内的闭包能够在函数返回之后被调用。因此,`customerProvider` 参数必须允许“逃逸”出函数作用域。 - diff --git a/source/chapter2/08_Enumerations.md b/source/chapter2/08_Enumerations.md index f05d2ef8..344424e7 100755 --- a/source/chapter2/08_Enumerations.md +++ b/source/chapter2/08_Enumerations.md @@ -267,6 +267,7 @@ let sunsetDirection = CompassPoint.west.rawValue ### 使用原始值初始化枚举实例 + 如果在定义枚举类型的时候使用了原始值,那么将会自动获得一个初始化方法,这个方法接收一个叫做`rawValue`的参数,参数类型即为原始值类型,返回值则是枚举成员或`nil`。你可以使用这个初始化方法来创建一个新的枚举实例。 这个例子利用原始值`7`创建了枚举成员`uranus`: diff --git a/source/chapter2/09_Classes_and_Structures.md b/source/chapter2/09_Classes_and_Structures.md index dc25a4c2..4815ba2a 100755 --- a/source/chapter2/09_Classes_and_Structures.md +++ b/source/chapter2/09_Classes_and_Structures.md @@ -142,6 +142,7 @@ print("The width of someVideoMode is now \(someVideoMode.resolution.width)") ### 结构体类型的成员逐一构造器 + 所有结构体都有一个自动生成的*成员逐一构造器*,用于初始化新结构体实例中成员的属性。新实例中各个属性的初始值可以通过属性的名称传递到成员逐一构造器之中: ```swift diff --git a/source/chapter2/11_Methods.md b/source/chapter2/11_Methods.md index 2a611974..b8e0605a 100755 --- a/source/chapter2/11_Methods.md +++ b/source/chapter2/11_Methods.md @@ -14,9 +14,9 @@ > 2.2 > 校对:[SketchK](https://github.com/SketchK) 2016-05-13 > 3.0.1,shanks,2016-11-13 - -> 4.0 -> 校对:[kemchenj](https://kemchenj.github.io/) 2017-09-21 + +> 4.0 +> 校对:[kemchenj](https://kemchenj.github.io/) 2017-09-21 本页包含内容: @@ -281,5 +281,3 @@ if player.tracker.advance(to: 6) { } // 打印 "level 6 has not yet been unlocked" ``` - - diff --git a/source/chapter2/14_Initialization.md b/source/chapter2/14_Initialization.md index 0b632e9d..ce6f28bd 100755 --- a/source/chapter2/14_Initialization.md +++ b/source/chapter2/14_Initialization.md @@ -403,12 +403,15 @@ convenience init(parameters) { 为了简化指定构造器和便利构造器之间的调用关系,Swift 采用以下三条规则来限制构造器之间的代理调用: ##### 规则 1 + 指定构造器必须调用其直接父类的的指定构造器。 ##### 规则 2 + 便利构造器必须调用*同*类中定义的其它构造器。 ##### 规则 3 + 便利构造器最后必须调用指定构造器。 一个更方便记忆的方法是: diff --git a/source/chapter2/18_Error_Handling.md b/source/chapter2/18_Error_Handling.md index 4c5d9bdd..5536bb8b 100755 --- a/source/chapter2/18_Error_Handling.md +++ b/source/chapter2/18_Error_Handling.md @@ -257,5 +257,3 @@ func processFile(filename: String) throws { > 注意 > 即使没有涉及到错误处理,你也可以使用`defer`语句。 - - diff --git a/source/chapter2/23_Generics.md b/source/chapter2/23_Generics.md index 333a6b6e..666099ba 100644 --- a/source/chapter2/23_Generics.md +++ b/source/chapter2/23_Generics.md @@ -694,4 +694,3 @@ extension Container { 综合一下,这些约束意味着,传入到 `indices` 下标,是一个整型的序列. (译者:原来的 `Container` 协议,`subscript` 必须是 `Int` 型的,扩展中新的 `subscript`,允许下标是一个的序列,而非单一的值。) - diff --git a/source/chapter2/24_Memory_Safe.md b/source/chapter2/24_Memory_Safe.md index d232f311..f6c90699 100644 --- a/source/chapter2/24_Memory_Safe.md +++ b/source/chapter2/24_Memory_Safe.md @@ -215,4 +215,3 @@ func someFunction() { > 4.0 > 翻译:[kemchenj](https://kemchenj.github.io/) 2017-09-21 - diff --git a/source/chapter2/25_Access_Control.md b/source/chapter2/25_Access_Control.md index 671de35c..f6cb4c63 100644 --- a/source/chapter2/25_Access_Control.md +++ b/source/chapter2/25_Access_Control.md @@ -46,6 +46,7 @@ Swift 不仅提供了多种不同的访问级别,还为某些典型场景提 ## 模块和源文件 + Swift 中的访问控制模型基于模块和源文件这两个概念。 模块指的是独立的代码单元,框架或应用程序会作为一个独立的模块来构建和发布。在 Swift 中,一个模块可以使用 `import` 关键字导入另外一个模块。 @@ -56,6 +57,7 @@ Swift 中的访问控制模型基于模块和源文件这两个概念。 ## 访问级别 + Swift 为代码中的实体提供了五种不同的*访问级别*。这些访问级别不仅与源文件中定义的实体相关,同时也与源文件所属的模块相关。 - *Open* 和 *Public* 级别可以让实体被同一模块源文件中的所有实体访问,在模块外也可以通过导入该模块来访问源文件里的所有实体。通常情况下,你会使用 Open 或 Public 级别来指定框架的外部接口。Open 和 Public 的区别在后面会提到。 @@ -426,5 +428,3 @@ extension SomeStruct: SomeProtocol { > 注意 这条规则也适用于为满足协议一致性而将类型别名用于关联类型的情况。 - - diff --git a/source/chapter3/03_Types.md b/source/chapter3/03_Types.md index 498b36f7..d3cccf37 100644 --- a/source/chapter3/03_Types.md +++ b/source/chapter3/03_Types.md @@ -87,15 +87,15 @@ var someValue: ExampleModule.MyType 元组类型是使用括号括起来的零个或多个类型,类型间用逗号隔开。 你可以使用元组类型作为一个函数的返回类型,这样就可以使函数返回多个值。你也可以命名元组类型中的元素,然后用这些名字来引用每个元素的值。元素的名字由一个标识符紧跟一个冒号 `(:)` 组成。[函数和多返回值](../chapter2/06_Functions.html#functions_with_multiple_return_values) 章节里有一个展示上述特性的例子。 - -当一个元组类型的元素有名字的时候,这个名字就是类型的一部分。 - + +当一个元组类型的元素有名字的时候,这个名字就是类型的一部分。 + ```swift -var someTuple = (top: 10, bottom: 12) // someTuple 的类型为 (top: Int, bottom: Int) -someTuple = (top: 4, bottom: 42) // 正确:命名类型匹配 -someTuple = (9, 99) // 正确:命名类型被自动推断 +var someTuple = (top: 10, bottom: 12) // someTuple 的类型为 (top: Int, bottom: Int) +someTuple = (top: 4, bottom: 42) // 正确:命名类型匹配 +someTuple = (9, 99) // 正确:命名类型被自动推断 someTuple = (left: 5, right: 5) // 错误:命名类型不匹配 -``` +``` `Void` 是空元组类型 `()` 的别名。如果括号内只有一个元素,那么该类型就是括号内元素的类型。比如,`(Int)` 的类型是 `Int` 而不是 `(Int)`。所以,只有当元组类型包含的元素个数在两个及以上时才可以命名元组元素。 @@ -107,7 +107,7 @@ someTuple = (left: 5, right: 5) // 错误:命名类型不匹配 > *元组类型元素* → [*元素名*](#element-name) [*类型注解*](#type-annotation) | [*类型*](#type) -> *元素名* → [*标识符*](02_Lexical_Structure.html#identifier) +> *元素名* → [*标识符*](02_Lexical_Structure.html#identifier) ## 函数类型 @@ -123,42 +123,42 @@ someTuple = (left: 5, right: 5) // 错误:命名类型不匹配 函数类型可以拥有一个可变长参数作为参数类型中的最后一个参数。从语法角度上讲,可变长参数由一个基础类型名字紧随三个点(`...`)组成,如 `Int...`。可变长参数被认为是一个包含了基础类型元素的数组。即 `Int...` 就是 `[Int]`。关于使用可变长参数的例子,请参阅 [可变参数](../chapter2/06_Functions.html#variadic_parameters)。 为了指定一个 `in-out` 参数,可以在参数类型前加 `inout` 前缀。但是你不可以对可变长参数或返回值类型使用 `inout`。关于这种参数的详细讲解请参阅 [输入输出参数](../chapter2/06_Functions.html#in_out_parameters)。 - -函数和方法中的参数名并不是函数类型的一部分。例如: - -```swift -func someFunction(left: Int, right: Int) {} -func anotherFunction(left: Int, right: Int) {} -func functionWithDifferentLabels(top: Int, bottom: Int) {} - -var f = someFunction // 函数f的类型为 (Int, Int) -> Void, 而不是 (left: Int, right: Int) -> Void. -f = anotherFunction // 正确 -f = functionWithDifferentLabels // 正确 - -func functionWithDifferentArgumentTypes(left: Int, right: String) {} -func functionWithDifferentNumberOfArguments(left: Int, right: Int, top: Int) {} - -f = functionWithDifferentArgumentTypes // 错误 -f = functionWithDifferentNumberOfArguments // 错误 -``` + +函数和方法中的参数名并不是函数类型的一部分。例如: + +```swift +func someFunction(left: Int, right: Int) {} +func anotherFunction(left: Int, right: Int) {} +func functionWithDifferentLabels(top: Int, bottom: Int) {} + +var f = someFunction // 函数f的类型为 (Int, Int) -> Void, 而不是 (left: Int, right: Int) -> Void. +f = anotherFunction // 正确 +f = functionWithDifferentLabels // 正确 + +func functionWithDifferentArgumentTypes(left: Int, right: String) {} +func functionWithDifferentNumberOfArguments(left: Int, right: Int, top: Int) {} + +f = functionWithDifferentArgumentTypes // 错误 +f = functionWithDifferentNumberOfArguments // 错误 +``` 如果一个函数类型包涵多个箭头(->),那么函数类型将从右向左进行组合。例如,函数类型 `Int -> Int -> Int` 可以理解为 `Int -> (Int -> Int)`,也就是说,该函数类型的参数为 `Int` 类型,其返回类型是一个参数类型为 `Int`,返回类型为 `Int` 的函数类型。 函数类型若要抛出错误就必须使用 `throws` 关键字来标记,若要重抛错误则必须使用 `rethrows` 关键字来标记。`throws` 关键字是函数类型的一部分,非抛出函数是抛出函数函数的一个子类型。因此,在使用抛出函数的地方也可以使用不抛出函数。抛出和重抛函数的相关描述见章节 [抛出函数与方法](05_Declarations.html#throwing_functions_and_methods) 和 [重抛函数与方法](05_Declarations.html#rethrowing_functions_and_methods)。 > 函数类型语法 - -> *函数类型* → [*特性列表*](06_Attributes.html#attributes)可选 [*函数类型子句*](#function-type-argument-clause) **throws**可选 **->** [*类型*](#type) -> *函数类型* → [*特性列表*](06_Attributes.html#attributes)可选 [*函数类型子句*](#function-type-argument-clause) **rethrows­** **->** [*类型*](#type) - -> *函数类型子句* → (­)­ -> *函数类型子句* → ([*函数类型参数列表*](#function-type-argument-list)*...*­可选)­ - -> *函数类型参数列表* → [*函数类型参数*](function-type-argument) | [*函数类型参数*](function-type-argument), [*函数类型参数列表*](#function-type-argument-list) - + +> *函数类型* → [*特性列表*](06_Attributes.html#attributes)可选 [*函数类型子句*](#function-type-argument-clause) **throws**可选 **->** [*类型*](#type) +> *函数类型* → [*特性列表*](06_Attributes.html#attributes)可选 [*函数类型子句*](#function-type-argument-clause) **rethrows­** **->** [*类型*](#type) + +> *函数类型子句* → (­)­ +> *函数类型子句* → ([*函数类型参数列表*](#function-type-argument-list)*...*­可选)­ + +> *函数类型参数列表* → [*函数类型参数*](function-type-argument) | [*函数类型参数*](function-type-argument), [*函数类型参数列表*](#function-type-argument-list) + > *函数类型参数* → [*特性列表*](06_Attributes.html#attributes)可选 **输入输出参数**可选 [*类型*](#type) | [*参数标签*](#argument-label) [*类型注解*](#type-annotation) -> *参数标签* → [*标识符*](02_Lexical_Structure.html#identifier) +> *参数标签* → [*标识符*](02_Lexical_Structure.html#identifier) ## 数组类型 @@ -258,17 +258,17 @@ var explicitlyUnwrappedString: Optional ``` 注意类型与 `!` 之间没有空格。 - -由于隐式解包修改了包涵其类型的声明语义,嵌套在元组类型或泛型的可选类型(比如字典元素类型或数组元素类型),不能被标记为隐式解包。例如: - -```swift -let tupleOfImplicitlyUnwrappedElements: (Int!, Int!) // 错误 -let implicitlyUnwrappedTuple: (Int, Int)! // 正确 - -let arrayOfImplicitlyUnwrappedElements: [Int!] // 错误 -let implicitlyUnwrappedArray: [Int]! // 正确 -``` - + +由于隐式解包修改了包涵其类型的声明语义,嵌套在元组类型或泛型的可选类型(比如字典元素类型或数组元素类型),不能被标记为隐式解包。例如: + +```swift +let tupleOfImplicitlyUnwrappedElements: (Int!, Int!) // 错误 +let implicitlyUnwrappedTuple: (Int, Int)! // 正确 + +let arrayOfImplicitlyUnwrappedElements: [Int!] // 错误 +let implicitlyUnwrappedArray: [Int]! // 正确 +``` + 由于隐式解析可选类型和可选类型有同样的表达式`Optional`,你可以在使用可选类型的地方使用隐式解析可选类型。比如,你可以将隐式解析可选类型的值赋给变量、常量和可选属性,反之亦然。 正如可选类型一样,你在声明隐式解析可选类型的变量或属性的时候也不用指定初始值,因为它有默认值 `nil`。 @@ -332,11 +332,11 @@ type(of: someInstance).printClassName() 可以使用恒等运算符(`===` 和 `!==`)来测试一个实例的运行时类型和它的编译时类型是否一致。 ```swift -if type(of: someInstance) === someInstance.self { - print("The dynamic and static type of someInstance are the same") -} else { - print("The dynamic and static type of someInstance are different") -} +if type(of: someInstance) === someInstance.self { + print("The dynamic and static type of someInstance are the same") +} else { + print("The dynamic and static type of someInstance are different") +} // 打印 "The dynamic and static type of someInstance are different" ``` @@ -396,5 +396,3 @@ let eFloat: Float = 2.71828 // eFloat 的类型为 Float ``` Swift 中的类型推断在单独的表达式或语句上进行。这意味着所有用于类型推断的信息必须可以从表达式或其某个子表达式的类型检查中获取到。 - - diff --git a/source/chapter3/06_Attributes.md b/source/chapter3/06_Attributes.md index bf4af714..845109d0 100755 --- a/source/chapter3/06_Attributes.md +++ b/source/chapter3/06_Attributes.md @@ -29,6 +29,7 @@ ##声明特性 + 声明特性只能应用于声明。 `available` @@ -180,6 +181,7 @@ NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv) ###Interface Builder 使用的声明特性 + `Interface Builder` 特性是 `Interface Builder` 用来与 Xcode 同步的声明特性。`Swift` 提供了以下的 `Interface Builder` 特性:`IBAction`,`IBOutlet`,`IBDesignable`,以及`IBInspectable` 。这些特性与 Objective-C 中对应的特性在概念上是相同的。 `IBOutlet` 和 `IBInspectable` 用于修饰一个类的属性声明,`IBAction` 特性用于修饰一个类的方法声明,`IBDesignable` 用于修饰类的声明。 @@ -188,6 +190,7 @@ NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv) ##类型特性 + 类型特性只能用于修饰类型。 `autoclosure` diff --git a/source/chapter3/10_Statements.md b/source/chapter3/10_Statements.md index ad8b3e75..3b019dbb 100755 --- a/source/chapter3/10_Statements.md +++ b/source/chapter3/10_Statements.md @@ -475,7 +475,7 @@ f() > *延迟语句* → **defer** [*代码块*](05_Declarations.md#code-block) -## Do 语句 +## Do 语句 `do` 语句用于引入一个新的作用域,该作用域中可以含有一个或多个 `catch` 子句,`catch` 子句中定义了一些匹配错误条件的模式。`do` 语句作用域内定义的常量和变量只能在 `do` 语句作用域内使用。 @@ -623,7 +623,7 @@ do { > *文件名* → [*静态字符串字面量*](02_Lexical_Structure.md#static-string-literal) -### 可用性条件 +### 可用性条件 可用性条件可作为 `if`,`while`,`guard` 语句的条件,可以在运行时基于特定的平台参数来查询 API 的可用性。 @@ -661,5 +661,3 @@ if #available(平台名称 版本, ..., *) { > *平台版本* → [十进制数字](02_Lexical_Structure.md#decimal-digits) > *平台版本* → [十进制数字](02_Lexical_Structure.md#decimal-digits) **.** [十进制数字](02_Lexical_Structure.md#decimal-digits) > *平台版本* → [十进制数字](02_Lexical_Structure.md#decimal-digits) **.** [十进制数字](02_Lexical_Structure.md#decimal-digits) **.** [十进制数字](02_Lexical_Structure.md#decimal-digits) - - diff --git a/source/chapter4/02_Type_Custom.md b/source/chapter4/02_Type_Custom.md index b7d463b5..8affad31 100644 --- a/source/chapter4/02_Type_Custom.md +++ b/source/chapter4/02_Type_Custom.md @@ -17,10 +17,12 @@ ####自定义原型 + 接下老码根据Bool的思想来创建一个OCBool类型,来让小伙伴们了解一下Swift中到底是怎么玩儿的。 来我们先看一下OCBool的定义。 #####代码示例如下: + ```swift enum OCBool{ case ocTrue @@ -35,6 +37,7 @@ case ocFalse ####实现默认值 + 行,我们给了一个漂亮的定义,不过按照传统语言的经验,Bool值默认情况下是假, 所以我们的OCBool也应该如此,我们使用类型扩展技术增加这个默认特性: ```swift extension OCBool{ @@ -45,11 +48,13 @@ extension OCBool{ ``` #####注意: + - 代码中第1行:extension关键字,非常强大,小伙伴们可以通过此创造出许多好玩的东西,建议各位去Github上看一个名为“Swiftz”的项目,它将扩展用到了极致。 - 代码中第3行:self = .ocFalse语法,刚入门的小伙伴们很迷糊,为什么会有奇怪的点语法,因为大牛Chris在Swift中增加了类型智能推断功能,在苹果Blog中,提到了“Context”概念,就是这个意思,因为这行语句是在枚举OCBool中的,其上下文就是OCBool的定义体,编译器当然知道.ocFalse就是OCBool.ocFalse了,所以这里直接点语法,非常整齐。 现在我们可以使用如下方法使用这个Bool类型。 #####代码示例如下: + ```swift var result:OCBool = OCBool() var result1:OCBool = .ocTrue @@ -57,6 +62,7 @@ var result1:OCBool = .ocTrue ####支持基本布尔型初始化 + 正如上述代码所述,我们只能通过类型或者枚举项目赋值,这是组合类型的用法,但是编码的日子里,我们总是希望和true,false直接打交道,也就是说,我们希望这么做, 代码示例如下: ```swift @@ -91,6 +97,7 @@ var isSuccess:OCBool = true ``` #####注意: + - 代码中的第11行是重点,我的类型OCBool支持了BooleanLiteralConvertible协议,这个协到底是干什么的呢,小伙伴们在Xcode代码编辑器,按住Command键,然后点击第11行中的BooleanLiteralConvertible协议名,则会进入它的定义, #####其定义如下: ```swift @@ -104,8 +111,11 @@ protocol BooleanLiteralConvertible { ####支持Bool类型判断 + 小伙伴们不安分, 肯定想着我怎么用它实现逻辑判断,所以如果你这么写, + #####代码示例如下: + ```swift var isSuccess:OCBool = true @@ -121,6 +131,7 @@ if isSuccess { OCBool现在只能用bool类型初始化,而不能直接返回bool型,小火把们还记得在《老码说编程之白话Swift江湖》中,老码多次提到,妈妈再也不担心我们 if a = 1{}的写法了, 因为等号不支持值返回了, 所以在if判断是后面的条件必须有返回值,OCBool没有,所以编译器哭了。我们解决这个问题。 #####代码示例如下: + ```swift import Foundation @@ -161,21 +172,26 @@ if isSuccess { ``` ####运行结果如下: + ``` Hello, World! 老码请你吃火锅! Program ended with exit code: 0 ``` + #####注意: + - 如果小伙伴们现在用的是Beta版的Xcode,注意苹果官方Blog中,在代码第17行如果在Xcode Beta4下是错误的,这里的协议是,LogicValue而不是BooleanVue,所以记得看错误提示才是好习惯。 - 注意代码第34行,完美支持if判断,且输出结果为“老码请你吃火锅”,老码也是说说而已,请不要当真。 ####支持兼容各们各派的类型 + 小伙伴们,江湖风险,门派众多,老码有自己的OCBool类型,可能嵩山少林有自己的SSBool类型,甚至连郭美美都可能有自己的MMBool类型,所以OCBool必须能够识别这些类型,这些各门各派的类型,只要支持LogicValue协议,就应该可以被识别,看老码怎么做, #####代码示例如下: + ```swift extension OCBool{ init( _ v: LogicValue ) @@ -200,6 +216,7 @@ if ocResult { ``` #####代码运行结果如下: + ``` Hello, World! 老码没钱,郭美美请你吃火锅! @@ -208,10 +225,12 @@ Program ended with exit code: 0 漂亮!我们的OCBool类型现在支持了所有的逻辑变量初始化。 #####注意: + - 代码中第2行:“_”下横杠的用法,这是一个功能强大的小强,在此的目的是屏蔽外部参数名,所以小伙伴们可以直接:var ocResult:OCBool = OCBool(mmResult)而不是:var ocResult:OCBool = OCBool(v: mmResult),小伙伴们惊呆了!这个init函数中本来就没有外部参数名啊,还记得老码在书里说过没,Swift的初始化函数会默认使用内部参数名,作为外部参数名。 ####完善OCBool的布尔基因体系: + 小伙伴们,bool类型的价值就是在于各种判断,诸如==,!=, &,|,^,!,以及各种组合逻辑运算,我们OCBool也要具备这些功能,否则就会基因缺陷,且看老码如何实现: ```swift diff --git a/source/chapter4/04_Interacting_with_C_Pointers.md b/source/chapter4/04_Interacting_with_C_Pointers.md index 79a09b2e..913142c9 100644 --- a/source/chapter4/04_Interacting_with_C_Pointers.md +++ b/source/chapter4/04_Interacting_with_C_Pointers.md @@ -14,6 +14,7 @@ Objective-C和C的API常常会需要用到指针。Swift中的数据类型都原生支持基于指针的Cocoa API,不仅如此,Swift会自动处理部分最常用的将指针作为参数传递的情况。这篇文章中,我们将着眼于在Swift中让C语言指针与变量、数组和字符串共同工作。 ####用以输入/输出的参数指针 + 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 @@ -32,6 +33,7 @@ if let contents = NSFileManager.defaultManager() 为了安全性,Swift要求被使用`&`传递的变量已经初始化。因为无法确定这个方法会不会在写入数据前尝试从指针中读取数据。 ####作为数组使用的参数指针 + 在C语言中,数组和指针的联系十分紧密,而Swift允许数组能够作为指针使用,从而与基于数组的C语言API协同工作更加简单。一个固定的数组可以使用一个常量指针直接传递,一个变化的数组可以用`&`运算符将一个非常量指针传递。就和输入/输出参数指针一样。举例来说:我们可以用Accelerate框架中的`vDSP_vadd`方法让两个数组`a`和`b`相加,并将结果写入第三个数组`result`。 ```swift import Accelerate @@ -45,7 +47,8 @@ vDSP_vadd(a, 1, b, 1, &result, 1, 4) // result now contains [1.5, 2.25, 3.125, 4.0625] ``` -#用作字符串参数的指针 +## 用作字符串参数的指针 + C语言中用`cont char*`指针来作为传递字符串的基本方式。Swift中的`String`可以被当作一个无限长度UTF-8编码的`const char*`指针来传递给方法。举例来说:我们可以直接传递一个字符串给一个标准C和POSIX库方法 ```swift puts("Hello from libc") @@ -60,10 +63,11 @@ if fd < 0 { } ``` -#指针参数转换的安全性 +## 指针参数转换的安全性 + Swift很努力地使与C语言指针的交互更加便利,因为它们广泛地存在于Cocoa之中,同时保持一定的安全性。然而,相比你的其他Swift代码与C语言的指针交互具有潜在的不安全性,所以务必要小心使用。其中特别要注意: - 如果被调用者为了在其返回值之后再次使用而保存了C指针的数据,那么这些转换使用起来并不安全。转换后的指针仅在调用期间保证有效。甚至你将同样的变量、数组或字符串作为多指针参数再次传递,你每次都会收到一个不同的指针。这个异常将全局或静态地储存为变量。你可以安全地将这段地址当作永久唯一的指针使用。例如:作为一个KVO上下文参数使用的时候。 - 当指针类型为`Array`或`String`时,溢出检查不是强制进行的。 基于C语言的API无法增加数组和字符串大小,所以在你将其传递到基于C语言的API之前,你必须确保数组或字符的大小正确。 -如果你需要使用基于指针的API时没有遵守以上指导,或是你重写了接受指针参数的Cocoa方法,于是你可以在Swift中直接用不安全的指针来使用未经处理的内存。在未来的文章中我们将着眼于更加高级的情况。 \ No newline at end of file +如果你需要使用基于指针的API时没有遵守以上指导,或是你重写了接受指针参数的Cocoa方法,于是你可以在Swift中直接用不安全的指针来使用未经处理的内存。在未来的文章中我们将着眼于更加高级的情况。 diff --git a/source/chapter4/05_Value_and_Reference_Types.md b/source/chapter4/05_Value_and_Reference_Types.md index f8b3ef96..d38b11b0 100644 --- a/source/chapter4/05_Value_and_Reference_Types.md +++ b/source/chapter4/05_Value_and_Reference_Types.md @@ -74,4 +74,3 @@ 本章节不是老码的原创,老码认真的阅读了苹果的官方博客,且自己的练习总结,如果小伙伴们费了吃奶的劲还是看不懂,请找度娘谷歌,还是看不懂请到老码[官方微博](http://weibo.com/u/5241713117)咆哮。 ##### 本文由翻译自Apple Swift Blog :[Value and Reference Types](https://developer.apple.com/swift/blog/?id=10) - diff --git a/source/chapter4/06_Access_Control_and_Protected.md b/source/chapter4/06_Access_Control_and_Protected.md index 8bbcf292..b19c281a 100644 --- a/source/chapter4/06_Access_Control_and_Protected.md +++ b/source/chapter4/06_Access_Control_and_Protected.md @@ -33,8 +33,3 @@ Swift的访问控制等级和继承无关,是单维度、非常清楚明了的 本章节不是老码的原创,是老码认真的阅读了苹果的官方博客,自己的练习总结,如果小伙伴们费了吃奶的劲还是看不懂,请找度娘谷歌。还是看不懂?请到老码[官方微博](http://weibo.com/u/5241713117)咆哮。 ##### 本文由翻译自Apple Swift Blog :[Access Control and Protected](原文地址:https://developer.apple.com/swift/blog/?id=11) - - - - -