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`。 ## 对方法的规定