From 4c3a75e7907fff00972feb106509e209e08fcc3d Mon Sep 17 00:00:00 2001 From: futantan Date: Mon, 29 Jun 2015 19:02:28 +0800 Subject: [PATCH 01/20] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E7=A4=BA=E4=BE=8B?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=20println()=20->=20print()?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/chapter2/22_Protocols.md | 52 ++++++++++++++++----------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/source/chapter2/22_Protocols.md b/source/chapter2/22_Protocols.md index d17abb5d..dad93021 100644 --- a/source/chapter2/22_Protocols.md +++ b/source/chapter2/22_Protocols.md @@ -1,4 +1,4 @@ -> 翻译:[geek5nan](https://github.com/geek5nan) +> 翻译:[geek5nan](https://github.com/geek5nan) > 校对:[dabing1022](https://github.com/dabing1022) # 协议 @@ -164,9 +164,9 @@ class LinearCongruentialGenerator: RandomNumberGenerator { } } let generator = LinearCongruentialGenerator() -println("Here's a random number: \(generator.random())") +print("Here's a random number: \(generator.random())") // 输出 : "Here's a random number: 0.37464991998171" -println("And another one: \(generator.random())") +print("And another one: \(generator.random())") // 输出 : "And another one: 0.729023776863283" ``` @@ -178,7 +178,7 @@ println("And another one: \(generator.random())") 如果协议中的实例方法打算改变其`遵循者`实例的类型,那么在协议定义时需要在方法前加`mutating`关键字,才能使`结构体,枚举`来采用并满足协议中对方法的规定。 ->注意: +>注意: >用`类`实现协议中的`mutating`方法时,不用写`mutating`关键字;用`结构体`,`枚举`实现协议中的`mutating`方法时,必须写`mutating`关键字。 如下所示,`Togglable`协议含有名为`toggle`的突变实例方法。根据名称推测,`toggle`方法应该是用于切换或恢复其`遵循者`实例或其属性的类型。 @@ -255,7 +255,7 @@ class SomeSuperClass { } } - + class SomeSubClass: SomeSuperClass, SomeProtocol { // "required" from SomeProtocol conformance; "override" from SomeSuperClass required override init() { @@ -277,7 +277,7 @@ class SomeSubClass: SomeSuperClass, SomeProtocol { 尽管`协议`本身并不实现任何功能,但是`协议`可以被当做类型来使用。 -使用场景: +使用场景: * `协议类型`作为函数、方法或构造器中的参数类型或返回值类型 * `协议类型`作为常量、变量或属性的类型 @@ -314,7 +314,7 @@ class Dice { ```swift var d6 = Dice(sides: 6,generator: LinearCongruentialGenerator()) for _ in 1...5 { - println("Random dice roll is \(d6.roll())") + print("Random dice roll is \(d6.roll())") } //输出结果 //Random dice roll is 3 @@ -333,7 +333,7 @@ for _ in 1...5 { 委托模式可以用来响应特定的动作或接收外部数据源提供的数据,而无需要知道外部数据源的所属类型(*译者注:只要求外部数据源`遵循`某协议*)。 -下文是两个基于骰子游戏的协议: +下文是两个基于骰子游戏的协议: ```swift protocol DiceGame { @@ -349,7 +349,7 @@ protocol DiceGameDelegate { ``` `DiceGame`协议可以在任意含有骰子的游戏中实现,`DiceGameDelegate`协议可以用来追踪`DiceGame`的游戏过程 - + 如下所示,`SnakesAndLadders`是`Snakes and Ladders`(译者注:[Control Flow](2)章节有该游戏的详细介绍)游戏的新版本。新版本使用`Dice`作为骰子,并且实现了`DiceGame`和`DiceGameDelegate`协议,后者用来记录游戏的过程: ```swift @@ -403,16 +403,16 @@ class DiceGameTracker: DiceGameDelegate { func gameDidStart(game: DiceGame) { numberOfTurns = 0 if game is SnakesAndLadders { - println("Started a new game of Snakes and Ladders") + print("Started a new game of Snakes and Ladders") } - println("The game is using a \(game.dice.sides)-sided dice") + print("The game is using a \(game.dice.sides)-sided dice") } func game(game: DiceGame, didStartNewTurnWithDiceRoll diceRoll: Int) { ++numberOfTurns - println("Rolled a \(diceRoll)") + print("Rolled a \(diceRoll)") } func gameDidEnd(game: DiceGame) { - println("The game lasted for \(numberOfTurns) turns") + print("The game lasted for \(numberOfTurns) turns") } } ``` @@ -468,7 +468,7 @@ extension Dice: TextRepresentable { ```swift let d12 = Dice(sides: 12,generator: LinearCongruentialGenerator()) -println(d12.asText()) +print(d12.asText()) // 输出 "A 12-sided dice" ``` @@ -480,7 +480,7 @@ extension SnakesAndLadders: TextRepresentable { return "A game of Snakes and Ladders with \(finalSquare) squares" } } -println(game.asText()) +print(game.asText()) // 输出 "A game of Snakes and Ladders with 25 squares" ``` @@ -504,7 +504,7 @@ extension Hamster: TextRepresentable {} ```swift let simonTheHamster = Hamster(name: "Simon") let somethingTextRepresentable: TextRepresentable = simonTheHamster -println(somethingTextRepresentable.asText()) +print(somethingTextRepresentable.asText()) // 输出 "A hamster named Simon" ``` @@ -523,7 +523,7 @@ let things: [TextRepresentable] = [game,d12,simonTheHamster] ```swift for thing in things { - println(thing.asText()) + print(thing.asText()) } // A game of Snakes and Ladders with 25 squares // A 12-sided dice @@ -583,7 +583,7 @@ extension SnakesAndLadders: PrettyTextRepresentable { 任意`SankesAndLadders`的实例都可以使用`asPrettyText()`方法。 ```swift -println(game.asPrettyText()) +print(game.asPrettyText()) // A game of Snakes and Ladders with 25 squares: // ○ ○ ▲ ○ ○ ▲ ○ ○ ▲ ▲ ○ ○ ○ ▼ ○ ○ ○ ○ ▼ ○ ○ ▼ ○ ▼ ○ ``` @@ -624,7 +624,7 @@ struct Person: Named, Aged { var age: Int } func wishHappyBirthday(celebrator: protocol) { - println("Happy birthday \(celebrator.name) - you're \(celebrator.age)!") + print("Happy birthday \(celebrator.name) - you're \(celebrator.age)!") } let birthdayPerson = Person(name: "Malcolm", age: 21) wishHappyBirthday(birthdayPerson) @@ -642,9 +642,9 @@ wishHappyBirthday(birthdayPerson) 使用`is`和`as`操作符来检查协议的一致性或转化协议类型。检查和转化的语法和之前相同(*详情查看[Typy Casting章节](5)*): -* `is`操作符用来检查实例是否`遵循`了某个`协议`。 +* `is`操作符用来检查实例是否`遵循`了某个`协议`。 * `as?`返回一个可选值,当实例`遵循`协议时,返回该协议类型;否则返回`nil` -* `as`用以强制向下转型。 +* `as`用以强制向下转型。 ```swift @objc protocol HasArea { @@ -697,9 +697,9 @@ let objects: [AnyObject] = [ ```swift for object in objects { if let objectWithArea = object as? HasArea { - println("Area is \(objectWithArea.area)") + print("Area is \(objectWithArea.area)") } else { - println("Something that doesn't have an area") + print("Something that doesn't have an area") } } // Area is 12.5663708 @@ -754,7 +754,7 @@ for object in objects { `count`属性用于存储当前的值,`increment`方法用来为`count`赋值。 `increment`方法通过`可选链`,尝试从两种`可选成员`中获取`count`。 - + 1. 由于`dataSource`可能为`nil`,因此在`dataSource`后边加上了`?`标记来表明只在`dataSource`非空时才去调用`incrementForCount`方法。 2. 即使`dataSource`存在,但是也无法保证其是否实现了`incrementForCount`方法,因此在`incrementForCount`方法后边也加有`?`标记 @@ -776,7 +776,7 @@ var counter = Counter() counter.dataSource = ThreeSource() for _ in 1...4 { counter.increment() - println(counter.count) + print(counter.count) } // 3 // 6 @@ -807,7 +807,7 @@ counter.count = -4 counter.dataSource = TowardsZeroSource() for _ in 1...5 { counter.increment() - println(counter.count) + print(counter.count) } // -3 // -2 From 148004f1624d156827b1d01b61de68142f41cc11 Mon Sep 17 00:00:00 2001 From: futantan Date: Mon, 29 Jun 2015 19:24:30 +0800 Subject: [PATCH 02/20] =?UTF-8?q?=E6=B7=BB=E5=8A=A02.0=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E9=83=A8=E5=88=86=E7=9A=84=E8=8B=B1=E6=96=87=EF=BC=8C=E5=B9=B6?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E6=B7=BB=E5=8A=A0=E9=83=A8=E5=88=86=E7=9A=84?= =?UTF-8?q?md=E6=A0=BC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/chapter2/22_Protocols.md | 76 +++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/source/chapter2/22_Protocols.md b/source/chapter2/22_Protocols.md index dad93021..3e31a805 100644 --- a/source/chapter2/22_Protocols.md +++ b/source/chapter2/22_Protocols.md @@ -815,3 +815,79 @@ for _ in 1...5 { // 0 // 0 ``` + +## Protocol Extensions + +Protocols can be extended to provide method and property implementations to conforming types. This allows you to define behavior on protocols themselves, rather than in each type’s individual conformance or in a global function. + +For example, the `RandomNumberGenerator` protocol can be extended to provide a `randomBool()` method, which uses the result of the required `random()` method to return a random `Bool` value: + +```swift +extension RandomNumberGenerator { + func randomBool() -> Bool { + return random() > 0.5 + } +} +``` + +By creating an extension on the protocol, all conforming types automatically gain this method implementation without any additional modification. + +```swift +let generator = LinearCongruentialGenerator() +print("Here's a random number: \(generator.random())") +// prints "Here's a random number: 0.37464991998171" +print("And here's a random Boolean: \(generator.randomBool())") +// prints "And here's a random Boolean: true" +``` + +### Providing Default Implementations + +You can use protocol extensions to provide a default implementation to any method or property requirement of that protocol. If a conforming type provides its own implementation of a required method or property, that implementation will be used instead of the one provided by the extension. + +> NOTE +> Protocol requirements with default implementations provided by extensions are distinct from optional protocol requirements. Although conforming types don’t have to provide their own implementation of either, requirements with default implementations can be called without optional chaining. + +For example, the `PrettyTextRepresentable` protocol, which inherits the `TextRepresentable` protocol can provide a default implementation of its required `asPrettyText()` method to simply return the result of the `asText()` method: + +```swift +extension PrettyTextRepresentable { + func asPrettyText() -> String { + return asText() + } +} +``` + +### Adding Constraints to Protocol Extensions + +When you define a protocol extension, you can specify constraints that conforming types must satisfy before the methods and properties of the extension are available. You write these constraints after the name of the protocol you’re extending using a `where` clause, as described in ([Where 子句](TODO)).: + +For instance, you can define an extension to the `CollectionType` protocol that applies to any collection whose elements conform to the `TextRepresentable protocol` from the example above. + +```swift +extension CollectionType where Generator.Element : TextRepresentable { + func asList() -> String { + return "(" + ", ".join(map({$0.asText()})) + ")" + } +} +``` + +The `asList()` method takes the textual representation of each element in the collection and concatenates them into a comma-separated list. + +Consider the `Hamster` structure from before, which conforms to the `TextRepresentable` protocol, and an array of `Hamster` values: + +```swift +let murrayTheHamster = Hamster(name: "Murray") +let morganTheHamster = Hamster(name: "Morgan") +let mauriceTheHamster = Hamster(name: "Maurice") +let hamsters = [murrayTheHamster, morganTheHamster, mauriceTheHamster] +``` + +Because `Array` conforms to `CollectionType`, and the array’s elements conform to the `TextRepresentable` protocol, the array can use the `asList()` method to get a textual representation of its contents: + +```swift +print(hamsters.asList()) +// prints "(A hamster named Murray, A hamster named Morgan, A hamster named Maurice)" +``` + +> NOTE +> If a conforming type satisfies the requirements for multiple constrained extensions that provide implementations for the same method or property, Swift will use the implementation corresponding to the most specialized constraints. From 97aaac1c2ca019f2a704e6f7c06cc112219e5b1b Mon Sep 17 00:00:00 2001 From: futantan Date: Mon, 29 Jun 2015 19:34:04 +0800 Subject: [PATCH 03/20] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=96=B0=E5=86=85?= =?UTF-8?q?=E5=AE=B9=E7=9A=84=E7=9B=AE=E5=BD=95=E8=B7=B3=E8=BD=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/chapter2/22_Protocols.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source/chapter2/22_Protocols.md b/source/chapter2/22_Protocols.md index 3e31a805..6589399d 100644 --- a/source/chapter2/22_Protocols.md +++ b/source/chapter2/22_Protocols.md @@ -21,6 +21,8 @@ - [协议合成(Protocol Composition)](#protocol_composition) - [检验协议的一致性(Checking for Protocol Conformance)](#checking_for_protocol_conformance) - [对可选协议的规定(Optional Protocol Requirements)](#optional_protocol_requirements) +- [协议扩展(Protocol Extensions)](#protocol_extensions) + `协议(Protocol)`用于定义完成某项任务或功能所必须的方法和属性,协议实际上并不提供这些功能或任务的具体`实现(Implementation)`--而只用来描述这些实现应该是什么样的。类,结构体,枚举通过提供协议所要求的方法,属性的具体实现来`采用(adopt)`协议。任意能够满足协议要求的类型被称为协议的`遵循者`。 @@ -816,7 +818,8 @@ for _ in 1...5 { // 0 ``` -## Protocol Extensions + +## 协议扩展 Protocols can be extended to provide method and property implementations to conforming types. This allows you to define behavior on protocols themselves, rather than in each type’s individual conformance or in a global function. From 145e4fadc8f9130070db76106f825f00fb718176 Mon Sep 17 00:00:00 2001 From: futantan Date: Fri, 3 Jul 2015 10:39:54 +0800 Subject: [PATCH 04/20] =?UTF-8?q?Protocols=20-=20=E5=AE=8C=E6=88=90?= =?UTF-8?q?=E6=A6=82=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/chapter2/22_Protocols.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/source/chapter2/22_Protocols.md b/source/chapter2/22_Protocols.md index 6589399d..c8cdb814 100644 --- a/source/chapter2/22_Protocols.md +++ b/source/chapter2/22_Protocols.md @@ -24,9 +24,7 @@ - [协议扩展(Protocol Extensions)](#protocol_extensions) -`协议(Protocol)`用于定义完成某项任务或功能所必须的方法和属性,协议实际上并不提供这些功能或任务的具体`实现(Implementation)`--而只用来描述这些实现应该是什么样的。类,结构体,枚举通过提供协议所要求的方法,属性的具体实现来`采用(adopt)`协议。任意能够满足协议要求的类型被称为协议的`遵循者`。 - -`协议`可以要求其`遵循者`提供特定的实例属性,实例方法,类方法,操作符或下标脚本等。 +`协议`定义了一个蓝图,规定了用来实现某一特定工作或者功能所必需的方法和属性。类,结构体或枚举类型都可以遵循协议,并提供具体实现来完成协议定义的方法和功能。任意能够满足协议要求的类型被称为`遵循(conform)`这个协议。 ## 协议的语法 From 1b59383d6cafc0dd517b1edac2b0adbb32428273 Mon Sep 17 00:00:00 2001 From: futantan Date: Fri, 3 Jul 2015 10:47:56 +0800 Subject: [PATCH 05/20] =?UTF-8?q?Protocols=20-=20=E5=AE=8C=E6=88=90Protoco?= =?UTF-8?q?l=20Syntax?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/chapter2/22_Protocols.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/chapter2/22_Protocols.md b/source/chapter2/22_Protocols.md index c8cdb814..e489cbe4 100644 --- a/source/chapter2/22_Protocols.md +++ b/source/chapter2/22_Protocols.md @@ -29,7 +29,7 @@ ## 协议的语法 -`协议`的定义方式与`类,结构体,枚举`的定义都非常相似,如下所示: +协议的定义方式与类,结构体,枚举的定义非常相似: ```swift protocol SomeProtocol { @@ -37,7 +37,7 @@ protocol SomeProtocol { } ``` -在类型名称后加上`协议名称`,中间以冒号`:`分隔即可实现协议;实现多个协议时,各协议之间用逗号`,`分隔,如下所示: +要使类遵循某个协议,需要在类型名称后加上协议名称,中间以冒号`:`分隔,作为类型定义的一部分。遵循多个协议时,各协议之间用逗号`,`分隔: ```swift struct SomeStructure: FirstProtocol, AnotherProtocol { @@ -45,7 +45,7 @@ struct SomeStructure: FirstProtocol, AnotherProtocol { } ``` -如果一个类在含有`父类`的同时也采用了协议,应当把`父类`放在所有的`协议`之前,如下所示: +如果类在遵循协议的同时拥有父类,应该将父类名放在协议名之前,以逗号分隔: ```swift class SomeClass: SomeSuperClass, FirstProtocol, AnotherProtocol { From 7e04e8d625c0c6600e85522796631c3eb768b533 Mon Sep 17 00:00:00 2001 From: futantan Date: Fri, 3 Jul 2015 10:49:38 +0800 Subject: [PATCH 06/20] =?UTF-8?q?=E6=9B=B4=E6=94=B9Property=20Requirements?= =?UTF-8?q?=E7=BF=BB=E8=AF=91->=20=E5=B1=9E=E6=80=A7=E8=A6=81=E6=B1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/chapter2/22_Protocols.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/chapter2/22_Protocols.md b/source/chapter2/22_Protocols.md index e489cbe4..215a500f 100644 --- a/source/chapter2/22_Protocols.md +++ b/source/chapter2/22_Protocols.md @@ -7,7 +7,7 @@ 本页包含内容: - [协议的语法(Protocol Syntax)](#protocol_syntax) -- [对属性的规定(Property Requirements)](#property_requirements) +- [属性要求(Property Requirements)](#property_requirements) - [对方法的规定(Method Requirements)](#method_requirements) - [对突变方法的规定(Mutating Method Requirements)](#mutating_method_requirements) - [对构造器的规定(Initializer Requirements)](#initializer_requirements) @@ -54,7 +54,7 @@ class SomeClass: SomeSuperClass, FirstProtocol, AnotherProtocol { ``` -## 对属性的规定 +## 属性要求 协议可以规定其`遵循者`提供特定名称与类型的`实例属性(instance property)`或`类属性(type property)`,而不管其是`存储型属性(stored property)`还是`计算型属性(calculate property)`。此外也可以指定属性是只读的还是可读写的。 From 9918eaf60898e77b648ea9498f2d1e4a0e44a235 Mon Sep 17 00:00:00 2001 From: futantan Date: Fri, 3 Jul 2015 15:04:44 +0800 Subject: [PATCH 07/20] =?UTF-8?q?Protocols=20-=20=E5=AE=8C=E6=88=90?= =?UTF-8?q?=E5=AF=B9=E5=B1=9E=E6=80=A7=E7=9A=84=E8=A7=84=E5=AE=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/chapter2/22_Protocols.md | 57 +++++++++++++++++---------------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/source/chapter2/22_Protocols.md b/source/chapter2/22_Protocols.md index 215a500f..ae226e8c 100644 --- a/source/chapter2/22_Protocols.md +++ b/source/chapter2/22_Protocols.md @@ -7,7 +7,7 @@ 本页包含内容: - [协议的语法(Protocol Syntax)](#protocol_syntax) -- [属性要求(Property Requirements)](#property_requirements) +- [对属性的规定(Property Requirements)](#property_requirements) - [对方法的规定(Method Requirements)](#method_requirements) - [对突变方法的规定(Mutating Method Requirements)](#mutating_method_requirements) - [对构造器的规定(Initializer Requirements)](#initializer_requirements) @@ -29,7 +29,7 @@ ## 协议的语法 -协议的定义方式与类,结构体,枚举的定义非常相似: +协议的定义方式与类,结构体,枚举的定义非常相似。 ```swift protocol SomeProtocol { @@ -37,7 +37,7 @@ protocol SomeProtocol { } ``` -要使类遵循某个协议,需要在类型名称后加上协议名称,中间以冒号`:`分隔,作为类型定义的一部分。遵循多个协议时,各协议之间用逗号`,`分隔: +要使类遵循某个协议,需要在类型名称后加上协议名称,中间以冒号`:`分隔,作为类型定义的一部分。遵循多个协议时,各协议之间用逗号`,`分隔。 ```swift struct SomeStructure: FirstProtocol, AnotherProtocol { @@ -45,7 +45,7 @@ struct SomeStructure: FirstProtocol, AnotherProtocol { } ``` -如果类在遵循协议的同时拥有父类,应该将父类名放在协议名之前,以逗号分隔: +如果类在遵循协议的同时拥有父类,应该将父类名放在协议名之前,以逗号分隔。 ```swift class SomeClass: SomeSuperClass, FirstProtocol, AnotherProtocol { @@ -54,13 +54,13 @@ class SomeClass: SomeSuperClass, FirstProtocol, AnotherProtocol { ``` -## 属性要求 +## 对属性的规定 -协议可以规定其`遵循者`提供特定名称与类型的`实例属性(instance property)`或`类属性(type property)`,而不管其是`存储型属性(stored property)`还是`计算型属性(calculate property)`。此外也可以指定属性是只读的还是可读写的。 +协议可以规定其`遵循者`提供特定名称和类型的`实例属性(instance property)`或`类属性(type property)`,而不指定是`存储型属性(stored property)`还是`计算型属性(calculate property)`。此外还必须指明是只读的还是可读可写的。 -如果协议要求属性是可读写的,那么这个属性不能是常量`存储型属性`或只读`计算型属性`;如果协议要求属性是只读的(gettable),那么`计算型属性`或`存储型属性`都能满足协议对属性的规定,在你的代码中,即使为只读属性实现了写方法(settable)也依然有效。 +如果协议要求属性是可读可写的,那么这个属性不能是常量或只读的计算属性。如果协议只要求属性是只读的(gettable),那个属性不仅可以是只读的,如果你代码需要的话,也可以是可写的。 -协议中的属性经常被加以`var`前缀声明其为变量属性,在声明后加上`{ set get }`来表示属性是可读写的,只读的属性则写作`{ get }`,如下所示: +协议中的通常用var来声明属性,在类型声明后加上`{ set get }`来表示属性是可读可写的,只读属性则用`{ get }`来表示。 ```swift protocol SomeProtocol { @@ -68,16 +68,17 @@ protocol SomeProtocol { var doesNotNeedToBeSettable: Int { get } } ``` - -如下所示,通常在协议的定义中使用`class`前缀表示该属性为类成员;在枚举和结构体实现协议时中,需要使用`static`关键字作为前缀。 + +在协议中定义类属性(type property)时,使用`static`关键字作为前缀。 +通常在协议的定义中使用`class`前缀表示该属性为类成员;在枚举和结构体实现协议时中,需要使用`static`关键字作为前缀。 ```swift protocol AnotherProtocol { - class var someTypeProperty: Int { get set } + static var someTypeProperty: Int { get set } } ``` -如下所示,这是一个含有一个实例属性要求的协议: +如下所示,这是一个含有一个实例属性要求的协议。 ```swift protocol FullyNamed { @@ -85,9 +86,9 @@ protocol FullyNamed { } ``` -`FullyNamed`协议定义了任何拥有`fullName`的类型。它并不指定具体类型,而只是要求类型必须提供一个`fullName`。任何`FullyNamed`类型都得有一个只读的`fullName`属性,类型为`String`。 +`FullyNamed`协议除了要求协议的遵循者提供fullName属性外,对协议对遵循者的类型并没有特别的要求。这个协议表示,任何遵循`FullyNamed`协议的类型,都具有一个可读的`String`类型实例属性`fullName`。 -如下所示,这是一个实现了`FullyNamed`协议的简单结构体: +下面是一个遵循`FullyNamed`协议的简单结构体。 ```swift struct Person: FullyNamed{ @@ -97,29 +98,29 @@ let john = Person(fullName: "John Appleseed") //john.fullName 为 "John Appleseed" ``` -这个例子中定义了一个叫做`Person`的结构体,用来表示具有指定名字的人。从第一行代码中可以看出,它采用了`FullyNamed`协议。 +这个例子中定义了一个叫做`Person`的结构体,用来表示具有名字的人。从第一行代码中可以看出,它遵循了`FullyNamed`协议。 -`Person`结构体的每一个实例都有一个叫做`fullName`,`String`类型的存储型属性,这正好匹配了`FullyNamed`协议的要求,也就意味着,`Person`结构体完整的`遵循`了协议。(如果协议要求未被完全满足,在编译时会报错) +`Person`结构体的每一个实例都有一个叫做`fullName`,`String`类型的存储型属性。这正好满足了`FullyNamed`协议的要求,也就意味着,`Person`结构体完整的`遵循`了协议。(如果协议要求未被完全满足,在编译时会报错) -这有一个更为复杂的类,它采用并实现了`FullyNamed`协议,如下所示: +下面是一个更为复杂的类,它采用并遵循了`FullyNamed`协议: ```swift class Starship: FullyNamed { - var prefix: String? - var name: String - init(name: String, prefix: String? = nil ) { - self.name = name - self.prefix = prefix - } - var fullName: String { - return (prefix != nil ? prefix! + " " : " ") + name - } + var prefix: String? + var name: String + init(name: String, prefix: String? = nil) { + self.name = name + self.prefix = prefix + } + var fullName: String { + return (prefix != nil ? prefix! + " " : "") + name + } } var ncc1701 = Starship(name: "Enterprise", prefix: "USS") -// ncc1701.fullName == "USS Enterprise" +// ncc1701.fullName is "USS Enterprise" ``` -`Starship`类把`fullName`属性实现为只读的`计算型属性`。每一个`Starship`类的实例都有一个名为`name`的必备属性和一个名为`prefix`的可选属性。 当`prefix`存在时,将`prefix`插入到`name`之前来为`Starship`构建`fullName`,`prefix`不存在时,则将直接用`name`构建`fullName` +Starship类把`fullName`属性实现为只读的计算型属性。每一个`Starship`类的实例都有一个名为`name`的属性和一个名为`prefix`的可选属性。 当`prefix`存在时,将`prefix`插入到`name`之前来为Starship构建`fullName`,`prefix`不存在时,则将直接用`name`构建`fullName`。 ## 对方法的规定 From 19e6b93d7897782d7d1cc418f65f64170ba07459 Mon Sep 17 00:00:00 2001 From: futantan Date: Fri, 3 Jul 2015 15:40:11 +0800 Subject: [PATCH 08/20] =?UTF-8?q?Protocols=20-=20=E5=AE=8C=E6=88=90?= =?UTF-8?q?=E5=AF=B9=E6=96=B9=E6=B3=95=E7=9A=84=E8=A7=84=E5=AE=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/chapter2/22_Protocols.md | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/source/chapter2/22_Protocols.md b/source/chapter2/22_Protocols.md index ae226e8c..78d6e9bf 100644 --- a/source/chapter2/22_Protocols.md +++ b/source/chapter2/22_Protocols.md @@ -9,7 +9,7 @@ - [协议的语法(Protocol Syntax)](#protocol_syntax) - [对属性的规定(Property Requirements)](#property_requirements) - [对方法的规定(Method Requirements)](#method_requirements) -- [对突变方法的规定(Mutating Method Requirements)](#mutating_method_requirements) +- [对Mutating方法的规定(Mutating Method Requirements)](#mutating_method_requirements) - [对构造器的规定(Initializer Requirements)](#initializer_requirements) - [协议类型(Protocols as Types)](#protocols_as_types) - [委托(代理)模式(Delegation)](#delegation) @@ -68,9 +68,8 @@ protocol SomeProtocol { var doesNotNeedToBeSettable: Int { get } } ``` - -在协议中定义类属性(type property)时,使用`static`关键字作为前缀。 -通常在协议的定义中使用`class`前缀表示该属性为类成员;在枚举和结构体实现协议时中,需要使用`static`关键字作为前缀。 + +在协议中定义类属性(type property)时,总是使用`static`关键字作为前缀。当协议的遵循者是类时,可以使用`class`或`static`关键字来声明类属性,但是在协议的定义中,仍然要使用`static`关键字。 ```swift protocol AnotherProtocol { @@ -125,20 +124,17 @@ Starship类把`fullName`属性实现为只读的计算型属性。每一个`Star ## 对方法的规定 -`协议`可以要求其`遵循者`实现某些指定的`实例方法`或`类方法`。这些方法作为协议的一部分,像普通的方法一样清晰的放在协议的定义中,而不需要大括号和方法体。 +协议可以要求其遵循者实现某些指定的实例方法或类方法。这些方法作为协议的一部分,像普通的方法一样放在协议的定义中,但是不需要大括号和方法体。可以在协议中定义具有可变参数的方法,和普通方法的定义方式相同。但是在协议的方法定义中,不支持参数默认值。 ->注意: ->协议中的方法支持`变长参数(variadic parameter)`,不支持`参数默认值(default value)`。 - -如下所示,协议中类方法的定义与类属性的定义相似,在协议定义的方法前置`class`关键字来表示。当在`枚举`或`结构体`实现类方法时,需要使用`static`关键字来代替。 +正如对属性的规定中所说的,在协议中定义类方法的时候,总是使用`static`关键字作为前缀。当协议的遵循者是类的时候,虽然你可以在类的实现中使用`class`或者`static`来实现类方法,但是在协议中声明类方法,仍然要使用`static`关键字。 ```swift protocol SomeProtocol { - class func someTypeMethod() + static func someTypeMethod() } ``` -如下所示,定义了含有一个实例方法的的协议。 +下面的例子定义了含有一个实例方法的协议。 ```swift protocol RandomNumberGenerator { @@ -146,7 +142,7 @@ protocol RandomNumberGenerator { } ``` -`RandomNumberGenerator`协议要求其`遵循者`必须拥有一个名为`random`, 返回值类型为`Double`的实例方法。 (尽管这里并未指明,但是我们假设返回值在[0,1]区间内)。 +`RandomNumberGenerator`协议要求其遵循者必须拥有一个名为`random`, 返回值类型为`Double`的实例方法。尽管这里并未指明,但是我们假设返回值在[0,1)区间内。 `RandomNumberGenerator`协议并不在意每一个随机数是怎样生成的,它只强调这里有一个随机数生成器。 @@ -172,7 +168,7 @@ print("And another one: \(generator.random())") ``` -## 对突变方法的规定 +## 对Mutating方法的规定 有时不得不在方法中更改实例的所属类型。在基于`值类型(value types)`(结构体,枚举)的实例方法中,将`mutating`关键字作为函数的前缀,写在`func`之前,表示可以在该方法中修改实例及其属性的所属类型。这一过程在[Modifyting Value Types from Within Instance Methods](1)章节中有详细描述。 From c6b818a4e11333805eb7cdd7a42c3e3bef8889ee Mon Sep 17 00:00:00 2001 From: futantan Date: Fri, 3 Jul 2015 16:19:41 +0800 Subject: [PATCH 09/20] =?UTF-8?q?Protocols=20-=20=E5=AF=B9Mutating?= =?UTF-8?q?=E6=96=B9=E6=B3=95=E7=9A=84=E8=A7=84=E5=AE=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/chapter2/22_Protocols.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/source/chapter2/22_Protocols.md b/source/chapter2/22_Protocols.md index 78d6e9bf..24a56bfa 100644 --- a/source/chapter2/22_Protocols.md +++ b/source/chapter2/22_Protocols.md @@ -170,15 +170,17 @@ print("And another one: \(generator.random())") ## 对Mutating方法的规定 -有时不得不在方法中更改实例的所属类型。在基于`值类型(value types)`(结构体,枚举)的实例方法中,将`mutating`关键字作为函数的前缀,写在`func`之前,表示可以在该方法中修改实例及其属性的所属类型。这一过程在[Modifyting Value Types from Within Instance Methods](1)章节中有详细描述。 +有时需要在方法中改变它的实例。例如,值类型(结构体,枚举)的实例方法中,将`mutating`关键字作为函数的前缀,写在`func`之前,表示可以在该方法中修改它所属的实例及其实例属性的值。这一过程在[Modifyting Value Types from Within Instance Methods](TODO)章节中有详细描述。 -如果协议中的实例方法打算改变其`遵循者`实例的类型,那么在协议定义时需要在方法前加`mutating`关键字,才能使`结构体,枚举`来采用并满足协议中对方法的规定。 +如果你在协议中定义了一个方法旨在改变遵循该协议的实例,那么在协议定义时需要在方法前加`mutating`关键字。这使得结构和枚举遵循协议并满足此方法要求。 >注意: ->用`类`实现协议中的`mutating`方法时,不用写`mutating`关键字;用`结构体`,`枚举`实现协议中的`mutating`方法时,必须写`mutating`关键字。 +>用类实现协议中的`mutating`方法时,不用写`mutating`关键字;用结构体,枚举实现协议中的`mutating`方法时,必须写`mutating`关键字。 -如下所示,`Togglable`协议含有名为`toggle`的突变实例方法。根据名称推测,`toggle`方法应该是用于切换或恢复其`遵循者`实例或其属性的类型。 +如下所示,`Togglable`协议含有名为`toggle`的实例方法。根据名称推测,`toggle()`方法将通过改变实例属性,来切换遵循该协议的实例的状态。 + +`toggle()`方法在定义的时候,使用`mutating`关键字标记,这表明当它被调用时该方法将会改变协议遵循者实例的状态。 ```swift protocol Togglable { @@ -186,9 +188,9 @@ protocol Togglable { } ``` -当使用`枚举`或`结构体`来实现`Togglabl`协议时,需要提供一个带有`mutating`前缀的`toggle`方法。 +当使用`枚举`或`结构体`来实现`Togglable`协议时,需要提供一个带有`mutating`前缀的`toggle`方法。 -如下所示,`OnOffSwitch`枚举`遵循`了`Togglable`协议,`On`,`Off`两个成员用于表示当前状态。枚举的`toggle`方法被标记为`mutating`,用以匹配`Togglabel`协议的规定。 +下面定义了一个名为`OnOffSwitch`的枚举类型。这个枚举类型在两种状态之间进行切换,用枚举成员`On`和`Off`表示。枚举类型的`toggle`方法被标记为`mutating`以满足`Togglable`协议的要求。 ```swift enum OnOffSwitch: Togglable { @@ -218,7 +220,7 @@ protocol SomeProtocol { } ``` -**协议构造器规定在类中的实现** +### 协议构造器规定在类中的实现 你可以在遵循该协议的类中实现构造器,并指定其为类的特定构造器或者便捷构造器。在这两种情况下,你都必须给构造器实现标上"required"修饰符: From 59883d153ae163ce6e7f08f9dbc1960a818cf868 Mon Sep 17 00:00:00 2001 From: futantan Date: Fri, 3 Jul 2015 16:20:42 +0800 Subject: [PATCH 10/20] =?UTF-8?q?Protocols=20-=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E4=BA=8C=E7=BA=A7=E6=A0=87=E9=A2=98markdown=E8=AF=AD=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/chapter2/22_Protocols.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/chapter2/22_Protocols.md b/source/chapter2/22_Protocols.md index 24a56bfa..e4cd628a 100644 --- a/source/chapter2/22_Protocols.md +++ b/source/chapter2/22_Protocols.md @@ -263,7 +263,7 @@ class SomeSubClass: SomeSuperClass, SomeProtocol { } ``` -**可失败构造器的规定** +### 可失败构造器的规定 可以通过给协议```Protocols```中添加可失败构造器来使遵循该协议的类型必须实现该可失败构造器。 From 0a097be9a2b6e2abd9a870de34019d5291e05e91 Mon Sep 17 00:00:00 2001 From: futantan Date: Sat, 4 Jul 2015 09:27:05 +0800 Subject: [PATCH 11/20] =?UTF-8?q?Protocols=20-=20=E5=AF=B9=E6=9E=84?= =?UTF-8?q?=E9=80=A0=E5=99=A8=E7=9A=84=E8=A7=84=E5=AE=9A=20=E7=BB=BC?= =?UTF-8?q?=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/chapter2/22_Protocols.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/chapter2/22_Protocols.md b/source/chapter2/22_Protocols.md index e4cd628a..01e68099 100644 --- a/source/chapter2/22_Protocols.md +++ b/source/chapter2/22_Protocols.md @@ -212,7 +212,7 @@ lightSwitch.toggle() ## 对构造器的规定 -协议可以要求它的遵循类型实现特定的构造器。你可以像书写普通的构造器那样,在协议的定义里写下构造器的需求,但不需要写花括号和构造器的实体: +协议可以要求它的遵循者实现指定的构造器。你可以像书写普通的构造器那样,在协议的定义里写下构造器的声明,但不需要写花括号和构造器的实体: ```swift protocol SomeProtocol { From ffe3303ba48f216c7b703bf8b5527f905350baf5 Mon Sep 17 00:00:00 2001 From: futantan Date: Sat, 4 Jul 2015 09:50:10 +0800 Subject: [PATCH 12/20] =?UTF-8?q?Protocols=20-=20=E5=AF=B9=E6=9E=84?= =?UTF-8?q?=E9=80=A0=E5=99=A8=E7=9A=84=E8=A7=84=E5=AE=9A=20=E5=8D=8F?= =?UTF-8?q?=E8=AE=AE=E6=9E=84=E9=80=A0=E5=99=A8=E8=A7=84=E5=AE=9A=E5=9C=A8?= =?UTF-8?q?=E7=B1=BB=E4=B8=AD=E7=9A=84=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/chapter2/22_Protocols.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/source/chapter2/22_Protocols.md b/source/chapter2/22_Protocols.md index 01e68099..8aeb1373 100644 --- a/source/chapter2/22_Protocols.md +++ b/source/chapter2/22_Protocols.md @@ -222,7 +222,7 @@ protocol SomeProtocol { ### 协议构造器规定在类中的实现 -你可以在遵循该协议的类中实现构造器,并指定其为类的特定构造器或者便捷构造器。在这两种情况下,你都必须给构造器实现标上"required"修饰符: +你可以在遵循该协议的类中实现构造器,并指定其为类的指定构造器(designated initializer)或者便利构造器(convenience initializer)。在这两种情况下,你都必须给构造器实现标上"required"修饰符: ```swift class SomeClass: SomeProtocol { @@ -234,11 +234,12 @@ class SomeClass: SomeProtocol { 使用`required`修饰符可以保证:所有的遵循该协议的子类,同样能为构造器规定提供一个显式的实现或继承实现。 -关于`required`构造器的更多内容,请参考`required`构造器 + +关于`required`构造器的更多内容,请参考`Required`构造器 + >注意 -> ->如果类已经被“final”修饰符所标示,你就不需要在协议构造器规定的实现中使用"required"修饰符。因为final类不能有子类。关于`final`修饰符的更多内容,请参见防止重写 +>如果类已经被标记为`final`,那么不需要在协议构造器的实现中使用`required`修饰符。因为final类不能有子类。关于`final`修饰符的更多内容,请参见防止重写 如果一个子类重写了父类的指定构造器,并且该构造器遵循了某个协议的规定,那么该构造器的实现需要被同时标示`required`和`override`修饰符 @@ -250,13 +251,13 @@ protocol SomeProtocol { class SomeSuperClass { init() { - //协议定义 + // 构造器的实现 } } class SomeSubClass: SomeSuperClass, SomeProtocol { - // "required" from SomeProtocol conformance; "override" from SomeSuperClass + // 因为遵循协议,需要加上"required"; 因为继承自父类,需要加上"override" required override init() { // 构造器实现 } @@ -265,7 +266,7 @@ class SomeSubClass: SomeSuperClass, SomeProtocol { ### 可失败构造器的规定 -可以通过给协议```Protocols```中添加可失败构造器来使遵循该协议的类型必须实现该可失败构造器。 +可以通过给协议`Protocols`中添加可失败构造器来使遵循该协议的类型必须实现该可失败构造器。 如果在协议中定义一个可失败构造器,则在遵顼该协议的类型中必须添加同名同参数的可失败构造器或非可失败构造器。 如果在协议中定义一个非可失败构造器,则在遵循该协议的类型中必须添加同名同参数的非可失败构造器或隐式解析类型的可失败构造器(`init!`)。 From 68b6028ee15fc662b5a2e74f88434fb808d2728e Mon Sep 17 00:00:00 2001 From: futantan Date: Sat, 4 Jul 2015 09:57:20 +0800 Subject: [PATCH 13/20] =?UTF-8?q?Protocols=20-=20=E5=AF=B9=E6=9E=84?= =?UTF-8?q?=E9=80=A0=E5=99=A8=E7=9A=84=E8=A7=84=E5=AE=9A=20=E5=8F=AF?= =?UTF-8?q?=E5=A4=B1=E8=B4=A5=E6=9E=84=E9=80=A0=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/chapter2/22_Protocols.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/source/chapter2/22_Protocols.md b/source/chapter2/22_Protocols.md index 8aeb1373..5f3f5dc2 100644 --- a/source/chapter2/22_Protocols.md +++ b/source/chapter2/22_Protocols.md @@ -268,8 +268,7 @@ class SomeSubClass: SomeSuperClass, SomeProtocol { 可以通过给协议`Protocols`中添加可失败构造器来使遵循该协议的类型必须实现该可失败构造器。 -如果在协议中定义一个可失败构造器,则在遵顼该协议的类型中必须添加同名同参数的可失败构造器或非可失败构造器。 -如果在协议中定义一个非可失败构造器,则在遵循该协议的类型中必须添加同名同参数的非可失败构造器或隐式解析类型的可失败构造器(`init!`)。 +如果在协议中定义一个可失败构造器,则在遵顼该协议的类型中必须添加同名同参数的可失败构造器或非可失败构造器。如果在协议中定义一个非可失败构造器,则在遵循该协议的类型中必须添加同名同参数的非可失败构造器或隐式解析类型的可失败构造器(`init!`)。 From a51a21f2f32b9da931c3c1b2fd67df6e69b802f0 Mon Sep 17 00:00:00 2001 From: futantan Date: Sat, 4 Jul 2015 10:14:16 +0800 Subject: [PATCH 14/20] =?UTF-8?q?Protocols=20-=20=E5=AE=8C=E6=88=90=20?= =?UTF-8?q?=E5=8D=8F=E8=AE=AE=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/chapter2/22_Protocols.md | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/source/chapter2/22_Protocols.md b/source/chapter2/22_Protocols.md index 5f3f5dc2..455f0db2 100644 --- a/source/chapter2/22_Protocols.md +++ b/source/chapter2/22_Protocols.md @@ -274,15 +274,16 @@ class SomeSubClass: SomeSuperClass, SomeProtocol { ## 协议类型 -尽管`协议`本身并不实现任何功能,但是`协议`可以被当做类型来使用。 +尽管协议本身并不实现任何功能,但是协议可以被当做类型来使用。 -使用场景: +协议可以像其他普通类型一样使用,使用场景: -* `协议类型`作为函数、方法或构造器中的参数类型或返回值类型 -* `协议类型`作为常量、变量或属性的类型 -* `协议类型`作为数组、字典或其他容器中的元素类型 +* 作为函数、方法或构造器中的参数类型或返回值类型 +* 作为常量、变量或属性的类型 +* 作为数组、字典或其他容器中的元素类型 -> 注意: 协议是一种类型,因此协议类型的名称应与其他类型(Int,Double,String)的写法相同,使用驼峰式写法 +> 注意 +> 协议是一种类型,因此协议类型的名称应与其他类型(Int,Double,String)的写法相同,使用大写字母开头的驼峰式写法,例如(`FullyNamed`和`RandomNumberGenerator`) 如下所示,这个示例中将协议当做类型来使用 @@ -300,18 +301,18 @@ class Dice { } ``` -例子中又一个`Dice`类,用来代表桌游中的拥有N个面的骰子。`Dice`的实例含有`sides`和`generator`两个属性,前者是整型,用来表示骰子有几个面,后者为骰子提供一个随机数生成器。 +例子中定义了一个`Dice`类,用来代表桌游中的拥有N个面的骰子。`Dice`的实例含有`sides`和`generator`两个属性,前者是整型,用来表示骰子有几个面,后者为骰子提供一个随机数生成器。 `generator`属性的类型为`RandomNumberGenerator`,因此任何遵循了`RandomNumberGenerator`协议的类型的实例都可以赋值给`generator`,除此之外,无其他要求。 -`Dice`类中也有一个`构造器(initializer)`,用来进行初始化操作。构造器中含有一个名为`generator`,类型为`RandomNumberGenerator`的形参。在调用构造方法时创建`Dice`的实例时,可以传入任何遵循`RandomNumberGenerator`协议的实例给generator。 +`Dice`类中也有一个构造器(initializer),用来进行初始化操作。构造器中含有一个名为`generator`,类型为`RandomNumberGenerator`的形参。在调用构造方法时创建`Dice`的实例时,可以传入任何遵循`RandomNumberGenerator`协议的实例给generator。 -`Dice`类也提供了一个名为`roll`的实例方法用来模拟骰子的面值。它先使用`generator`的`random`方法来创建一个[0-1]区间内的随机数种子,然后加工这个随机数种子生成骰子的面值。generator被认为是遵循了`RandomNumberGenerator`的类型,因而保证了`random`方法可以被调用。 +`Dice`类也提供了一个名为`roll`的实例方法用来模拟骰子的面值。它先使用`generator`的`random()`方法来创建一个[0,1)区间内的随机数,然后使用这个随机数生成正确的骰子面值。因为generator遵循了`RandomNumberGenerator`协议,因而保证了`random`方法可以被调用。 -如下所示,这里展示了如何使用`LinearCongruentialGenerator`的实例作为随机数生成器创建一个六面骰子: +下面的例子展示了如何使用`LinearCongruentialGenerator`的实例作为随机数生成器创建一个六面骰子: ```swift -var d6 = Dice(sides: 6,generator: LinearCongruentialGenerator()) +var d6 = Dice(sides: 6, generator: LinearCongruentialGenerator()) for _ in 1...5 { print("Random dice roll is \(d6.roll())") } From a8ec9464bd88fea0caf9b12089a5e83daaa96460 Mon Sep 17 00:00:00 2001 From: futantan Date: Sat, 4 Jul 2015 10:51:06 +0800 Subject: [PATCH 15/20] =?UTF-8?q?Protocols=20-=20=E5=AE=8C=E6=88=90?= =?UTF-8?q?=E5=A7=94=E6=89=98(=E4=BB=A3=E7=90=86)=E6=A8=A1=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/chapter2/22_Protocols.md | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/source/chapter2/22_Protocols.md b/source/chapter2/22_Protocols.md index 455f0db2..a5828e9f 100644 --- a/source/chapter2/22_Protocols.md +++ b/source/chapter2/22_Protocols.md @@ -327,13 +327,9 @@ for _ in 1...5 { ## 委托(代理)模式 -委托是一种设计模式(*译者注: 想起了那年 UITableViewDelegate 中的奔跑,那是我逝去的Objective-C。。。*),它允许`类`或`结构体`将一些需要它们负责的功能`交由(委托)`给其他的类型的实例。 +委托是一种设计模式,它允许`类`或`结构体`将一些需要它们负责的功能`交由(委托)`给其他的类型的实例。委托模式的实现很简单: 定义协议来封装那些需要被委托的函数和方法, 使其`遵循者`拥有这些被委托的`函数和方法`。委托模式可以用来响应特定的动作或接收外部数据源提供的数据,而无需要知道外部数据源的类型信息。 -委托模式的实现很简单: 定义`协议`来`封装`那些需要被委托的`函数和方法`, 使其`遵循者`拥有这些被委托的`函数和方法`。 - -委托模式可以用来响应特定的动作或接收外部数据源提供的数据,而无需要知道外部数据源的所属类型(*译者注:只要求外部数据源`遵循`某协议*)。 - -下文是两个基于骰子游戏的协议: +下面的例子是两个基于骰子游戏的协议: ```swift protocol DiceGame { @@ -348,7 +344,7 @@ protocol DiceGameDelegate { } ``` -`DiceGame`协议可以在任意含有骰子的游戏中实现,`DiceGameDelegate`协议可以用来追踪`DiceGame`的游戏过程 +`DiceGame`协议可以在任意含有骰子的游戏中实现。`DiceGameDelegate`协议可以用来追踪`DiceGame`的游戏过程 如下所示,`SnakesAndLadders`是`Snakes and Ladders`(译者注:[Control Flow](2)章节有该游戏的详细介绍)游戏的新版本。新版本使用`Dice`作为骰子,并且实现了`DiceGame`和`DiceGameDelegate`协议,后者用来记录游戏的过程: @@ -385,15 +381,15 @@ class SnakesAndLadders: DiceGame { } ``` -这个版本的游戏封装到了`SnakesAndLadders`类中,该类采用了`DiceGame`协议,并且提供了`dice`属性和`play`实例方法用来`遵循`协议。(`dice`属性在构造之后就不在改变,且协议只要求`dice`为只读的,因此将`dice`声明为常量属性。) +这个版本的游戏封装到了`SnakesAndLadders`类中,该类遵循了`DiceGame`协议,并且提供了相应的可读的`dice`属性和`play`实例方法。(`dice`属性在构造之后就不再改变,且协议只要求`dice`为只读的,因此将`dice`声明为常量属性。) 在`SnakesAndLadders`类的`构造器(initializer)`初始化游戏。所有的游戏逻辑被转移到了`play`方法中,`play`方法使用协议规定的`dice`属性提供骰子摇出的值。 -> 注意:`delegate`并不是游戏的必备条件,因此`delegate`被定义为遵循`DiceGameDelegate`协议的可选属性,`delegate`使用`nil`作为初始值。 +注意:`delegate`并不是游戏的必备条件,因此`delegate`被定义为遵循`DiceGameDelegate`协议的可选属性。因为`delegate`是可选值,因此在初始化的时候被自动赋值为`nil`。随后,可以在游戏中为`delegate`设置适当的值。 `DicegameDelegate`协议提供了三个方法用来追踪游戏过程。被放置于游戏的逻辑中,即`play()`方法内。分别在游戏开始时,新一轮开始时,游戏结束时被调用。 -因为`delegate`是一个遵循`DiceGameDelegate`的可选属性,因此在`play()`方法中使用了`可选链`来调用委托方法。 若`delegate`属性为`nil`, 则delegate所调用的方法失效。若`delegate`不为`nil`,则方法能够被调用 +因为`delegate`是一个遵循`DiceGameDelegate`的可选属性,因此在`play()`方法中使用了`可选链`来调用委托方法。 若`delegate`属性为`nil`, 则delegate所调用的方法失效,并不会产生错误。若`delegate`不为`nil`,则方法能够被调用 如下所示,`DiceGameTracker`遵循了`DiceGameDelegate`协议 From 4a7fedf46e999e21a13a23b932ca5ab46af59d41 Mon Sep 17 00:00:00 2001 From: futantan Date: Sat, 4 Jul 2015 20:10:44 +0800 Subject: [PATCH 16/20] =?UTF-8?q?Protocols=20-=20=E5=AE=8C=E6=88=90?= =?UTF-8?q?=E5=A7=94=E6=89=98(=E4=BB=A3=E7=90=86)=E6=A8=A1=E5=BC=8F=20?= =?UTF-8?q?=E6=A0=A1=E5=AF=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/chapter2/22_Protocols.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/chapter2/22_Protocols.md b/source/chapter2/22_Protocols.md index a5828e9f..0b9fc63b 100644 --- a/source/chapter2/22_Protocols.md +++ b/source/chapter2/22_Protocols.md @@ -383,7 +383,7 @@ class SnakesAndLadders: DiceGame { 这个版本的游戏封装到了`SnakesAndLadders`类中,该类遵循了`DiceGame`协议,并且提供了相应的可读的`dice`属性和`play`实例方法。(`dice`属性在构造之后就不再改变,且协议只要求`dice`为只读的,因此将`dice`声明为常量属性。) -在`SnakesAndLadders`类的`构造器(initializer)`初始化游戏。所有的游戏逻辑被转移到了`play`方法中,`play`方法使用协议规定的`dice`属性提供骰子摇出的值。 +游戏使用`SnakesAndLadders`类的`构造器(initializer)`初始化游戏。所有的游戏逻辑被转移到了协议中的`play`方法,`play`方法使用协议规定的`dice`属性提供骰子摇出的值。 注意:`delegate`并不是游戏的必备条件,因此`delegate`被定义为遵循`DiceGameDelegate`协议的可选属性。因为`delegate`是可选值,因此在初始化的时候被自动赋值为`nil`。随后,可以在游戏中为`delegate`设置适当的值。 @@ -413,7 +413,7 @@ class DiceGameTracker: DiceGameDelegate { } ``` -`DiceGameTracker`实现了`DiceGameDelegate`协议规定的三个方法,用来记录游戏已经进行的轮数。 当游戏开始时,`numberOfTurns`属性被赋值为0; 在每新一轮中递加; 游戏结束后,输出打印游戏的总轮数。 +`DiceGameTracker`实现了`DiceGameDelegate`协议规定的三个方法,用来记录游戏已经进行的轮数。 当游戏开始时,`numberOfTurns`属性被赋值为0; 在每新一轮中递增; 游戏结束后,输出打印游戏的总轮数。 `gameDidStart`方法从`game`参数获取游戏信息并输出。`game`在方法中被当做`DiceGame`类型而不是`SnakeAndLadders`类型,所以方法中只能访问`DiceGame`协议中的成员。当然了,这些方法也可以在类型转换之后调用。在上例代码中,通过`is`操作符检查`game`是否为 `SnakesAndLadders`类型的实例,如果是,则打印出相应的内容。 From 857dcd619a4da1b190f721e8e5374e811bd90c33 Mon Sep 17 00:00:00 2001 From: futantan Date: Sat, 4 Jul 2015 20:27:43 +0800 Subject: [PATCH 17/20] =?UTF-8?q?Protocols=20-=20=E5=AE=8C=E6=88=90?= =?UTF-8?q?=E5=9C=A8=E6=89=A9=E5=B1=95=E4=B8=AD=E6=B7=BB=E5=8A=A0=E5=8D=8F?= =?UTF-8?q?=E8=AE=AE=E6=88=90=E5=91=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/chapter2/22_Protocols.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/source/chapter2/22_Protocols.md b/source/chapter2/22_Protocols.md index 0b9fc63b..b09b6335 100644 --- a/source/chapter2/22_Protocols.md +++ b/source/chapter2/22_Protocols.md @@ -417,7 +417,7 @@ class DiceGameTracker: DiceGameDelegate { `gameDidStart`方法从`game`参数获取游戏信息并输出。`game`在方法中被当做`DiceGame`类型而不是`SnakeAndLadders`类型,所以方法中只能访问`DiceGame`协议中的成员。当然了,这些方法也可以在类型转换之后调用。在上例代码中,通过`is`操作符检查`game`是否为 `SnakesAndLadders`类型的实例,如果是,则打印出相应的内容。 -无论当前进行的是何种游戏,`game`都遵循`DiceGame`协议以确保`game`含有`dice`属性,因此在`gameDidStart`方法中可以通过传入的`game`参数来访问`dice`属性,进而打印出`dice`的`sides`属性的值。 +无论当前进行的是何种游戏,`game`都遵循`DiceGame`协议以确保`game`含有`dice`属性,因此在`gameDidStart(_:)`方法中可以通过传入的`game`参数来访问`dice`属性,进而打印出`dice`的`sides`属性的值。 `DiceGameTracker`的运行情况,如下所示: @@ -438,11 +438,12 @@ game.play() ## 在扩展中添加协议成员 -即便无法修改源代码,依然可以通过`扩展(Extension)`来扩充已存在类型(*译者注: 类,结构体,枚举等*)。`扩展`可以为已存在的类型添加`属性`,`方法`,`下标脚本`,`协议`等成员。详情请在[扩展](4)章节中查看。 +即便无法修改源代码,依然可以通过扩展(Extension)来扩充已存在类型(*译者注: 类,结构体,枚举等*)。扩展可以为已存在的类型添加属性,方法,下标脚本,协议等成员。详情请在[扩展](4)章节中查看。 -> 注意: 通过`扩展`为已存在的类型`遵循`协议时,该类型的所有实例也会随之添加协议中的方法 +> 注意 +> 通过扩展为已存在的类型遵循协议时,该类型的所有实例也会随之添加协议中的方法 -`TextRepresentable`协议含有一个`asText`,如下所示: +例如`TextRepresentable`协议,任何想要表示一些文本内容的类型都可以遵循该协议。这些想要表示的内容可以是类型本身的描述,也可以是当前内容的版本: ```swift protocol TextRepresentable { @@ -450,7 +451,7 @@ protocol TextRepresentable { } ``` -通过`扩展`为上一节中提到的`Dice`类遵循`TextRepresentable`协议 +可以通过扩展,为上一节中提到的`Dice`增加类遵循`TextRepresentable`协议的功能 ```swift extension Dice: TextRepresentable { @@ -459,8 +460,9 @@ extension Dice: TextRepresentable { } } ``` +现在,通过扩展使得`Dice`类型遵循了一个新的协议,这和`Dice`类型在定义的时候声明为遵循`TextRepresentable`协议的效果相同。在扩展的时候,协议名称写在类型名之后,以冒号隔开,在大括号内写明新添加的协议内容。 -从现在起,`Dice`类型的实例可被当作`TextRepresentable`类型: +现在所有`Dice`的实例都遵循了`TextRepresentable`协议: ```swift let d12 = Dice(sides: 12,generator: LinearCongruentialGenerator()) @@ -468,7 +470,7 @@ print(d12.asText()) // 输出 "A 12-sided dice" ``` -`SnakesAndLadders`类也可以通过`扩展`的方式来遵循协议: +同样`SnakesAndLadders`类也可以通过`扩展`的方式来遵循`TextRepresentable`协议: ```swift extension SnakesAndLadders: TextRepresentable { From 866097add001d2f7c9b7f3c912b4c86c33a0f088 Mon Sep 17 00:00:00 2001 From: futantan Date: Sat, 4 Jul 2015 20:31:06 +0800 Subject: [PATCH 18/20] =?UTF-8?q?Protocols=20-=20=E5=AE=8C=E6=88=90?= =?UTF-8?q?=E9=80=9A=E8=BF=87=E6=89=A9=E5=B1=95=E8=A1=A5=E5=85=85=E5=8D=8F?= =?UTF-8?q?=E8=AE=AE=E5=A3=B0=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/chapter2/22_Protocols.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source/chapter2/22_Protocols.md b/source/chapter2/22_Protocols.md index b09b6335..7ca35ac4 100644 --- a/source/chapter2/22_Protocols.md +++ b/source/chapter2/22_Protocols.md @@ -485,7 +485,7 @@ print(game.asText()) ## 通过扩展补充协议声明 -当一个类型已经实现了协议中的所有要求,却没有声明时,可以通过`扩展`来补充协议声明: +当一个类型已经实现了协议中的所有要求,却没有声明为遵循该协议时,可以通过扩展(空的扩展体)来补充协议声明: ```swift struct Hamster { @@ -506,7 +506,8 @@ print(somethingTextRepresentable.asText()) // 输出 "A hamster named Simon" ``` -> 注意: 即使满足了协议的所有要求,类型也不会自动转变,因此你必须为它做出明显的协议声明 +> 注意 +> 即使满足了协议的所有要求,类型也不会自动转变,因此你必须为它做出显式的协议声明 ## 集合中的协议类型 From 17751155281e0bf8b0ce8183b8df28c487e8fefa Mon Sep 17 00:00:00 2001 From: futantan Date: Sat, 4 Jul 2015 20:55:07 +0800 Subject: [PATCH 19/20] =?UTF-8?q?Protocols=20-=20=E5=AE=8C=E6=88=90?= =?UTF-8?q?=E9=9B=86=E5=90=88=E4=B8=AD=E7=9A=84=E5=8D=8F=E8=AE=AE=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/chapter2/22_Protocols.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/chapter2/22_Protocols.md b/source/chapter2/22_Protocols.md index 7ca35ac4..f9aaa911 100644 --- a/source/chapter2/22_Protocols.md +++ b/source/chapter2/22_Protocols.md @@ -512,13 +512,13 @@ print(somethingTextRepresentable.asText()) ## 集合中的协议类型 -协议类型可以被集合使用,表示集合中的元素均为协议类型: +协议类型可以在集合使用,表示集合中的元素均为协议类型,下面的例子创建了一个类型为`TextRepresentable`的数组: ```swift let things: [TextRepresentable] = [game,d12,simonTheHamster] ``` -如下所示,`things`数组可以被直接遍历,并调用其中元素的`asText()`函数: +如下所示,`things`数组可以被直接遍历,并打印每个元素的文本表示: ```swift for thing in things { From 6062b84363714e2573bfbb79500b7a5839478a28 Mon Sep 17 00:00:00 2001 From: futantan Date: Sat, 4 Jul 2015 21:24:35 +0800 Subject: [PATCH 20/20] =?UTF-8?q?Protocols=20-=20=E5=AE=8C=E6=88=90?= =?UTF-8?q?=E5=8D=8F=E8=AE=AE=E7=9A=84=E7=BB=A7=E6=89=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/chapter2/22_Protocols.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/source/chapter2/22_Protocols.md b/source/chapter2/22_Protocols.md index f9aaa911..0933d597 100644 --- a/source/chapter2/22_Protocols.md +++ b/source/chapter2/22_Protocols.md @@ -534,7 +534,7 @@ for thing in things { ## 协议的继承 -协议能够继承一到多个其他协议。语法与类的继承相似,多个协议间用逗号`,`分隔 +协议能够继承一个或多个其他协议,可以在继承的协议基础上增加新的内容要求。协议的继承语法与类的继承相似,多个被继承的协议间用逗号分隔: ```swift protocol InheritingProtocol: SomeProtocol, AnotherProtocol { @@ -550,9 +550,9 @@ protocol PrettyTextRepresentable: TextRepresentable { } ``` -遵循`PrettyTextRepresentable`协议的同时,也需要遵循`TextRepresentable`协议。 +例子中定义了一个新的协议`PrettyTextRepresentable`,它继承自`TextRepresentable`协议。任何遵循`PrettyTextRepresentable`协议的类型在满足该协议的要求时,也必须满足`TextRepresentable`协议的要求。在这个例子中,`PrettyTextRepresentable`协议要求其遵循者提供一个返回值为`String`类型的`asPrettyText`方法。 -如下所示,用`扩展`为`SnakesAndLadders`遵循`PrettyTextRepresentable`协议: +如下所示,扩展`SnakesAndLadders`,让其遵循`PrettyTextRepresentable`协议: ```swift extension SnakesAndLadders: PrettyTextRepresentable { @@ -573,11 +573,11 @@ extension SnakesAndLadders: PrettyTextRepresentable { } ``` -在`for in`中迭代出了`board`数组中的每一个元素: +上述扩展使得`SnakesAndLadders`遵循了`PrettyTextRepresentable`协议,并为每个`SnakesAndLadders`类型提供了了协议要求的`asPrettyText()`方法。每个`PrettyTextRepresentable`类型同时也是`TextRepresentable`类型,所以在`asPrettyText`的实现中,可以调用`asText()`方法。之后在每一行加上换行符,作为输出的开始。然后遍历数组中的元素,输出一个几何图形来表示遍历的结果: -* 当从数组中迭代出的元素的值大于0时,用`▲`表示 -* 当从数组中迭代出的元素的值小于0时,用`▼`表示 -* 当从数组中迭代出的元素的值等于0时,用`○`表示 +* 当从数组中取出的元素的值大于0时,用`▲`表示 +* 当从数组中取出的元素的值小于0时,用`▼`表示 +* 当从数组中取出的元素的值等于0时,用`○`表示 任意`SankesAndLadders`的实例都可以使用`asPrettyText()`方法。