From 03fb94ea6dc3530c2d6233139e96f9239b730081 Mon Sep 17 00:00:00 2001 From: Siyu Yang Date: Tue, 30 Jun 2015 21:02:54 +0800 Subject: [PATCH 1/6] Chapter2_Properties Section1_Stored_Properties finished --- source/chapter2/10_Properties.md | 42 +++++++++++++++++--------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/source/chapter2/10_Properties.md b/source/chapter2/10_Properties.md index bf305032..4070c1c2 100755 --- a/source/chapter2/10_Properties.md +++ b/source/chapter2/10_Properties.md @@ -1,5 +1,5 @@ > 翻译:[shinyzhu](https://github.com/shinyzhu) -> 校对:[pp-prog](https://github.com/pp-prog) +> 校对:[pp-prog](https://github.com/pp-prog) [yangsiy](https://github.com/yangsiy) # 属性 (Properties) --- @@ -12,16 +12,16 @@ - [全局变量和局部变量(Global and Local Variables)](#global_and_local_variables) - [类型属性(Type Properties)](#type_properties) -**属性**将值跟特定的类、结构或枚举关联。存储属性存储常量或变量作为实例的一部分,计算属性计算(而不是存储)一个值。计算属性可以用于类、结构体和枚举里,存储属性只能用于类和结构体。 +*属性*将值跟特定的类、结构或枚举关联。存储属性存储常量或变量作为实例的一部分,而计算属性计算(不是存储)一个值。计算属性可以用于类、结构体和枚举,存储属性只能用于类和结构体。 -存储属性和计算属性通常用于特定类型的实例,但是,属性也可以直接用于类型本身,这种属性称为类型属性。 +存储属性和计算属性通常与特定类型的实例关联。但是,属性也可以直接作用于类型本身,这种属性称为类型属性。 -另外,还可以定义属性观察器来监控属性值的变化,以此来触发一个自定义的操作。属性观察器可以添加到自己写的存储属性上,也可以添加到从父类继承的属性上。 +另外,还可以定义属性观察器来监控属性值的变化,以此来触发一个自定义的操作。属性观察器可以添加到自己定义的存储属性上,也可以添加到从父类继承的属性上。 ## 存储属性 -简单来说,一个存储属性就是存储在特定类或结构体的实例里的一个常量或变量,存储属性可以是*变量存储属性*(用关键字`var`定义),也可以是*常量存储属性*(用关键字`let`定义)。 +简单来说,一个存储属性就是存储在特定类或结构体的实例里的一个常量或变量。存储属性可以是*变量存储属性*(用关键字`var`定义),也可以是*常量存储属性*(用关键字`let`定义)。 可以在定义存储属性的时候指定默认值,请参考[构造过程](../chapter2/14_Initialization.html)一章的[默认属性值](../chapter2/14_Initialization.html#default_property_values)一节。也可以在构造过程中设置或修改存储属性的值,甚至修改常量存储属性的值,请参考[构造过程](../chapter2/14_Initialization.html)一章的[在初始化阶段修改常量存储属性](../chapter2/14_Initialization.html#modifying_constant_properties_during_initialization)一节。 @@ -38,12 +38,12 @@ rangeOfThreeItems.firstValue = 6 // 该区间现在表示整数6,7,8 ``` -`FixedLengthRange`的实例包含一个名为`firstValue`的变量存储属性和一个名为`length`的常量存储属性。在上面的例子中,`length`在创建实例的时候被赋值,因为它是一个常量存储属性,所以之后无法修改它的值。 +`FixedLengthRange`的实例包含一个名为`firstValue`的变量存储属性和一个名为`length`的常量存储属性。在上面的例子中,`length`在创建实例的时候被初始化,因为它是一个常量存储属性,所以之后无法修改它的值。 -### 常量和存储属性 +### 常量结构体的存储属性 -如果创建了一个结构体的实例并赋值给一个常量,则无法修改实例的任何属性,即使定义了变量存储属性: +如果创建了一个结构体的实例并将其赋值给一个常量,则无法修改该实例的任何属性,即使定义了变量存储属性: ```swift let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4) @@ -52,11 +52,11 @@ rangeOfFourItems.firstValue = 6 // 尽管 firstValue 是个变量属性,这里还是会报错 ``` -因为`rangeOfFourItems`声明成了常量(用`let`关键字),即使`firstValue`是一个变量属性,也无法再修改它了。 +因为`rangeOfFourItems`被声明成了常量(用`let`关键字),即使`firstValue`是一个变量属性,也无法再修改它了。 这种行为是由于结构体(struct)属于*值类型*。当值类型的实例被声明为常量的时候,它的所有属性也就成了常量。 -属于*引用类型*的类(class)则不一样,把一个引用类型的实例赋给一个常量后,仍然可以修改实例的变量属性。 +属于*引用类型*的类(class)则不一样。把一个引用类型的实例赋给一个常量后,仍然可以修改该实例的变量属性。 ### 延迟存储属性 @@ -64,11 +64,11 @@ rangeOfFourItems.firstValue = 6 延迟存储属性是指当第一次被调用的时候才会计算其初始值的属性。在属性声明前使用`lazy`来标示一个延迟存储属性。 > 注意: -> 必须将延迟存储属性声明成变量(使用`var`关键字),因为属性的值在实例构造完成之前可能无法得到。而常量属性在构造过程完成之前必须要有初始值,因此无法声明成延迟属性。 +> 必须将延迟存储属性声明成变量(使用`var`关键字),因为属性的初始值可能在实例构造完成之后才会得到。而常量属性在构造过程完成之前必须要有初始值,因此无法声明成延迟属性。 -延迟属性很有用,当属性的值依赖于在实例的构造过程结束前无法知道具体值的外部因素时,或者当属性的值需要复杂或大量计算时,可以只在需要的时候来计算它。 +延迟属性很有用,当属性的值依赖于在实例的构造过程结束后才会知道具体值的外部因素时,或者当获得属性的初始值需要复杂或大量计算时,可以只在需要的时候计算它。 -下面的例子使用了延迟存储属性来避免复杂类的不必要的初始化。例子中定义了`DataImporter`和`DataManager`两个类,下面是部分代码: +下面的例子使用了延迟存储属性来避免复杂类中不必要的初始化。例子中定义了`DataImporter`和`DataManager`两个类,下面是部分代码: ```swift class DataImporter { @@ -94,25 +94,27 @@ manager.data.append("Some more data") `DataManager`类包含一个名为`data`的存储属性,初始值是一个空的字符串(`String`)数组。虽然没有写出全部代码,`DataManager`类的目的是管理和提供对这个字符串数组的访问。 -`DataManager`的一个功能是从文件导入数据,该功能由`DataImporter`类提供,`DataImporter`需要消耗不少时间完成初始化:因为它的实例在初始化时可能要打开文件,还要读取文件内容到内存。 +`DataManager`的一个功能是从文件导入数据。该功能由`DataImporter`类提供,`DataImporter`完成初始化需要消耗不少时间:因为它的实例在初始化时可能要打开文件,还要读取文件内容到内存。 -`DataManager`也可能不从文件中导入数据。所以当`DataManager`的实例被创建时,没必要创建一个`DataImporter`的实例,更明智的是当用到`DataImporter`的时候才去创建它。 +`DataManager`也可能不从文件中导入数据就完成了管理数据的功能。所以当`DataManager`的实例被创建时,没必要创建一个`DataImporter`的实例,更明智的是当第一次用到`DataImporter`的时候才去创建它。 由于使用了`lazy`,`importer`属性只有在第一次被访问的时候才被创建。比如访问它的属性`fileName`时: ```swift -println(manager.importer.fileName) +print(manager.importer.fileName) // DataImporter 实例的 importer 属性现在被创建了 // 输出 "data.txt” -``` +``` + +> 注意: +> 如果一个被标记为`lazy`的属性在没有初始化时就同时被多个线程访问,则无法保证该属性只会被初始化一次。 ### 存储属性和实例变量 -如果您有过 Objective-C 经验,应该知道Objective-C为类实例存储值和引用提供两种方法。对于属性来说,也可以使用实例变量作为属性值的后端存储。 +如果您有过 Objective-C 经验,应该知道 Objective-C 为类实例存储值和引用提供两种方法。对于属性来说,也可以使用实例变量作为属性值的后端存储。 -Swift 编程语言中把这些理论统一用属性来实现。Swift 中的属性没有对应的实例变量,属性的后端存储也无法直接访问。这就避免了不同场景下访问方式的困扰,同时也将属性的定义简化成一个语句。 -一个类型中属性的全部信息——包括命名、类型和内存管理特征——都在唯一一个地方(类型定义中)定义。 +Swift 编程语言中把这些理论统一用属性来实现。Swift 中的属性没有对应的实例变量,属性的后端存储也无法直接访问。这就避免了不同场景下访问方式的困扰,同时也将属性的定义简化成一个语句。一个类型中属性的全部信息——包括命名、类型和内存管理特征——都在唯一一个地方(类型定义中)定义。 ## 计算属性 From 1c9b0ceae795d53130c64b1a364b90053e766750 Mon Sep 17 00:00:00 2001 From: Siyu Yang Date: Tue, 30 Jun 2015 22:14:26 +0800 Subject: [PATCH 2/6] Chapter2_Properties Section2_Computed_Properties finished --- source/chapter2/10_Properties.md | 62 ++++++++++++++++---------------- 1 file changed, 30 insertions(+), 32 deletions(-) diff --git a/source/chapter2/10_Properties.md b/source/chapter2/10_Properties.md index 4070c1c2..4e645540 100755 --- a/source/chapter2/10_Properties.md +++ b/source/chapter2/10_Properties.md @@ -119,7 +119,7 @@ Swift 编程语言中把这些理论统一用属性来实现。Swift 中的属 ## 计算属性 -除存储属性外,类、结构体和枚举可以定义*计算属性*,计算属性不直接存储值,而是提供一个 getter 来获取值,一个可选的 setter 来间接设置其他属性或变量的值。 +除存储属性外,类、结构体和枚举可以定义*计算属性*。计算属性不直接存储值,而是提供一个 getter 和一个可选的 setter,来间接获取和设置其他属性或变量的值。 ```swift struct Point { @@ -132,38 +132,38 @@ struct Rect { var origin = Point() var size = Size() var center: Point { - get { - let centerX = origin.x + (size.width / 2) - let centerY = origin.y + (size.height / 2) - return Point(x: centerX, y: centerY) - } - set(newCenter) { - origin.x = newCenter.x - (size.width / 2) - origin.y = newCenter.y - (size.height / 2) - } + get { + let centerX = origin.x + (size.width / 2) + let centerY = origin.y + (size.height / 2) + return Point(x: centerX, y: centerY) + } + set(newCenter) { + origin.x = newCenter.x - (size.width / 2) + origin.y = newCenter.y - (size.height / 2) + } } } var square = Rect(origin: Point(x: 0.0, y: 0.0), size: Size(width: 10.0, height: 10.0)) let initialSquareCenter = square.center square.center = Point(x: 15.0, y: 15.0) -println("square.origin is now at (\(square.origin.x), \(square.origin.y))") +print("square.origin is now at (\(square.origin.x), \(square.origin.y))") // 输出 "square.origin is now at (10.0, 10.0)” ``` -这个例子定义了 3 个几何形状的结构体: +这个例子定义了 3 个结构体来描述几何形状: - `Point`封装了一个`(x, y)`的坐标 -- `Size`封装了一个`width`和`height` +- `Size`封装了一个`width`和一个`height` - `Rect`表示一个有原点和尺寸的矩形 -`Rect`也提供了一个名为`center`的计算属性。一个矩形的中心点可以从原点和尺寸来算出,所以不需要将它以显式声明的`Point`来保存。`Rect`的计算属性`center`提供了自定义的 getter 和 setter 来获取和设置矩形的中心点,就像它有一个存储属性一样。 +`Rect`也提供了一个名为`center`的计算属性。一个矩形的中心点可以从原点(`origin`)和尺寸(`size`)算出,所以不需要将它以显式声明的`Point`来保存。`Rect`的计算属性`center`提供了自定义的 getter 和 setter 来获取和设置矩形的中心点,就像它有一个存储属性一样。 -例子中接下来创建了一个名为`square`的`Rect`实例,初始值原点是`(0, 0)`,宽度高度都是`10`。如图所示蓝色正方形。 +上述例子中创建了一个名为`square`的`Rect`实例,初始值原点是`(0, 0)`,宽度高度都是`10`。如下图中蓝色正方形所示。 -`square`的`center`属性可以通过点运算符(`square.center`)来访问,这会调用 getter 来获取属性的值。跟直接返回已经存在的值不同,getter 实际上通过计算然后返回一个新的`Point`来表示`square`的中心点。如代码所示,它正确返回了中心点`(5, 5)`。 +`square`的`center`属性可以通过点运算符(`square.center`)来访问,这会调用该属性的 getter 来获取它的值。跟直接返回已经存在的值不同,getter 实际上通过计算然后返回一个新的`Point`来表示`square`的中心点。如代码所示,它正确返回了中心点`(5, 5)`。 -`center`属性之后被设置了一个新的值`(15, 15)`,表示向右上方移动正方形到如图所示橙色正方形的位置。设置属性`center`的值会调用 setter 来修改属性`origin`的`x`和`y`的值,从而实现移动正方形到新的位置。 +`center`属性之后被设置了一个新的值`(15, 15)`,表示向右上方移动正方形到如下图橙色正方形所示的位置。设置属性`center`的值会调用它的 setter 来修改属性`origin`的`x`和`y`的值,从而实现移动正方形到新的位置。 Computed Properties sample @@ -177,15 +177,15 @@ struct AlternativeRect { var origin = Point() var size = Size() var center: Point { - get { - let centerX = origin.x + (size.width / 2) - let centerY = origin.y + (size.height / 2) - return Point(x: centerX, y: centerY) - } - set { - origin.x = newValue.x - (size.width / 2) - origin.y = newValue.y - (size.height / 2) - } + get { + let centerX = origin.x + (size.width / 2) + let centerY = origin.y + (size.height / 2) + return Point(x: centerX, y: centerY) + } + set { + origin.x = newValue.x - (size.width / 2) + origin.y = newValue.y - (size.height / 2) + } } } ``` @@ -195,26 +195,24 @@ struct AlternativeRect { 只有 getter 没有 setter 的计算属性就是*只读计算属性*。只读计算属性总是返回一个值,可以通过点运算符访问,但不能设置新的值。 -> 注意: -> +> 注意: > 必须使用`var`关键字定义计算属性,包括只读计算属性,因为它们的值不是固定的。`let`关键字只用来声明常量属性,表示初始化后再也无法修改的值。 - 只读计算属性的声明可以去掉`get`关键字和花括号: ```swift struct Cuboid { var width = 0.0, height = 0.0, depth = 0.0 var volume: Double { - return width * height * depth + return width * height * depth } } let fourByFiveByTwo = Cuboid(width: 4.0, height: 5.0, depth: 2.0) -println("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)") +print("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)") // 输出 "the volume of fourByFiveByTwo is 40.0" ``` -这个例子定义了一个名为`Cuboid`的结构体,表示三维空间的立方体,包含`width`、`height`和`depth`属性,还有一个名为`volume`的只读计算属性用来返回立方体的体积。设置`volume`的值毫无意义,因为通过`width`、`height`和`depth`就能算出`volume`。然而,`Cuboid`提供一个只读计算属性来让外部用户直接获取体积是很有用的。 +这个例子定义了一个名为`Cuboid`的结构体,表示三维空间的立方体,包含`width`、`height`和`depth`属性。结构体还有一个名为`volume`的只读计算属性用来返回立方体的体积。设置`volume`的值毫无意义,因为无法确定修改`width`、`height`和`depth`三者中的哪些值来匹配新的`volume`,从而造成歧义。然而,`Cuboid`提供一个只读计算属性来让外部用户直接获取体积是很有用的。 ## 属性观察器 From 44f55a7a860abee52f81980f6c5d2615daccf6ab Mon Sep 17 00:00:00 2001 From: Siyu Yang Date: Wed, 1 Jul 2015 10:35:21 +0800 Subject: [PATCH 3/6] Chapter2_Properties Section3_Property_Observers finished --- source/chapter2/10_Properties.md | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/source/chapter2/10_Properties.md b/source/chapter2/10_Properties.md index 4e645540..43e53c0c 100755 --- a/source/chapter2/10_Properties.md +++ b/source/chapter2/10_Properties.md @@ -222,34 +222,33 @@ print("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)") 可以为除了延迟存储属性之外的其他存储属性添加属性观察器,也可以通过重载属性的方式为继承的属性(包括存储属性和计算属性)添加属性观察器。属性重载请参考[继承](chapter/13_Inheritance.html)一章的[重载](chapter/13_Inheritance.html#overriding)。 > 注意: -> 不需要为无法重载的计算属性添加属性观察器,因为可以通过 setter 直接监控和响应值的变化。 +> 不需要为非重载的计算属性添加属性观察器,因为可以通过它的 setter 直接监控和响应值的变化。 可以为属性添加如下的一个或全部观察器: -- `willSet`在设置新的值之前调用 +- `willSet`在新的值被设置之前调用 - `didSet`在新的值被设置之后立即调用 -`willSet`观察器会将新的属性值作为固定参数传入,在`willSet`的实现代码中可以为这个参数指定一个名称,如果不指定则参数仍然可用,这时使用默认名称`newValue`表示。 +`willSet`观察器会将新的属性值作为常量参数传入,在`willSet`的实现代码中可以为这个参数指定一个名称,如果不指定则参数仍然可用,这时使用默认名称`newValue`表示。 类似地,`didSet`观察器会将旧的属性值作为参数传入,可以为该参数命名或者使用默认参数名`oldValue`。 -> 注意: -> +> 注意: > `willSet`和`didSet`观察器在属性初始化过程中不会被调用,它们只会当属性的值在初始化之外的地方被设置时被调用。 -这里是一个`willSet`和`didSet`的实际例子,其中定义了一个名为`StepCounter`的类,用来统计当人步行时的总步数,可以跟计步器或其他日常锻炼的统计装置的输入数据配合使用。 +这里是一个`willSet`和`didSet`的实际例子,其中定义了一个名为`StepCounter`的类,用来统计当人步行时的总步数。这个类可以跟计步器或其他日常锻炼的统计装置的输入数据配合使用。 ```swift class StepCounter { var totalSteps: Int = 0 { - willSet(newTotalSteps) { - println("About to set totalSteps to \(newTotalSteps)") - } - didSet { - if totalSteps > oldValue { - println("Added \(totalSteps - oldValue) steps") + willSet(newTotalSteps) { + print("About to set totalSteps to \(newTotalSteps)") + } + didSet { + if totalSteps > oldValue { + print("Added \(totalSteps - oldValue) steps") + } } - } } } let stepCounter = StepCounter() @@ -270,10 +269,10 @@ stepCounter.totalSteps = 896 例子中的`willSet`观察器将表示新值的参数自定义为`newTotalSteps`,这个观察器只是简单的将新的值输出。 -`didSet`观察器在`totalSteps`的值改变后被调用,它把新的值和旧的值进行对比,如果总的步数增加了,就输出一个消息表示增加了多少步。`didSet`没有提供自定义名称,所以默认值`oldValue`表示旧值的参数名。 +`didSet`观察器在`totalSteps`的值改变后被调用,它把新的值和旧的值进行对比,如果总的步数增加了,就输出一个消息表示增加了多少步。`didSet`没有为旧的值提供自定义名称,所以默认值`oldValue`表示旧值的参数名。 > 注意: -> 如果在`didSet`观察器里为属性赋值,这个值会替换观察器之前设置的值。 +> 如果在一个属性的`didSet`观察器里为它赋值,这个值会替换该观察器之前设置的值。 ##全局变量和局部变量 From 2779cda3e9eff07d8f9159fb57b7eabc5bf0ccf4 Mon Sep 17 00:00:00 2001 From: Siyu Yang Date: Wed, 1 Jul 2015 15:56:14 +0800 Subject: [PATCH 4/6] Chapter2_Properties Section4&5 finished --- source/chapter2/10_Properties.md | 77 +++++++++++++++++--------------- 1 file changed, 40 insertions(+), 37 deletions(-) diff --git a/source/chapter2/10_Properties.md b/source/chapter2/10_Properties.md index 43e53c0c..12f80f0b 100755 --- a/source/chapter2/10_Properties.md +++ b/source/chapter2/10_Properties.md @@ -277,11 +277,11 @@ stepCounter.totalSteps = 896 ##全局变量和局部变量 -计算属性和属性观察器所描述的模式也可以用于*全局变量*和*局部变量*,全局变量是在函数、方法、闭包或任何类型之外定义的变量,局部变量是在函数、方法或闭包内部定义的变量。 +计算属性和属性观察器所描述的模式也可以用于*全局变量*和*局部变量*。全局变量是在函数、方法、闭包或任何类型之外定义的变量。局部变量是在函数、方法或闭包内部定义的变量。 前面章节提到的全局或局部变量都属于存储型变量,跟存储属性类似,它提供特定类型的存储空间,并允许读取和写入。 -另外,在全局或局部范围都可以定义计算型变量和为存储型变量定义观察器,计算型变量跟计算属性一样,返回一个计算的值而不是存储值,声明格式也完全一样。 +另外,在全局或局部范围都可以定义计算型变量和为存储型变量定义观察器。计算型变量跟计算属性一样,返回一个计算的值而不是存储值,声明格式也完全一样。 > 注意: > 全局的常量或变量都是延迟计算的,跟[延迟存储属性](#lazy_stored_properties)相似,不同的地方在于,全局的常量或变量不需要标记`lazy`特性。 @@ -296,9 +296,7 @@ stepCounter.totalSteps = 896 类型属性用于定义特定类型所有实例共享的数据,比如所有实例都能用的一个常量(就像 C 语言中的静态常量),或者所有实例都能访问的一个变量(就像 C 语言中的静态变量)。 -对于值类型(指结构体和枚举)可以定义存储型和计算型类型属性,对于类(class)则只能定义计算型类型属性。 - -值类型的存储型类型属性可以是变量或常量,计算型类型属性跟实例的计算属性一样定义成变量属性。 +值类型的存储型类型属性可以是变量或常量,计算型类型属性跟实例的计算属性一样只能定义成变量属性。 > 注意: > 跟实例的存储属性不同,必须给存储型类型属性指定默认值,因为类型本身无法在初始化过程中使用构造器给类型属性赋值。 @@ -306,26 +304,30 @@ stepCounter.totalSteps = 896 ###类型属性语法 -在 C 或 Objective-C 中,静态常量和静态变量的定义是通过特定类型加上`global`关键字。在 Swift 编程语言中,类型属性是作为类型定义的一部分写在类型最外层的花括号内,因此它的作用范围也就在类型支持的范围内。 +在 C 或 Objective-C 中,与某个类型关联的静态常量和静态变量,是作为全局(*global*)静态变量定义的。但是在 Swift 编程语言中,类型属性是作为类型定义的一部分写在类型最外层的花括号内,因此它的作用范围也就在类型支持的范围内。 -使用关键字`static`来定义值类型的类型属性,关键字`class`来为类(class)定义类型属性。下面的例子演示了存储型和计算型类型属性的语法: +使用关键字`static`来定义类型属性。在为类(class)定义计算型类型属性时,可以使用关键字`class`来支持子类对父类的实现进行重写。下面的例子演示了存储型和计算型类型属性的语法: ```swift struct SomeStructure { static var storedTypeProperty = "Some value." static var computedTypeProperty: Int { - // 这里返回一个 Int 值 + return 1 } } enum SomeEnumeration { static var storedTypeProperty = "Some value." static var computedTypeProperty: Int { - // 这里返回一个 Int 值 + return 6 } } -class SomeClass { - class var computedTypeProperty: Int { - // 这里返回一个 Int 值 +class SomeClass { + static var storedTypeProperty = "Some value." + static var computedTypeProperty: Int { + return 27 + } + class var overrideableComputedTypeProperty: Int { + return 107 } } ``` @@ -336,17 +338,18 @@ class SomeClass { ###获取和设置类型属性的值 -跟实例的属性一样,类型属性的访问也是通过点运算符来进行,但是,类型属性是通过类型本身来获取和设置,而不是通过实例。比如: +跟实例的属性一样,类型属性的访问也是通过点运算符来进行。但是,类型属性是通过类型本身来获取和设置,而不是通过实例。比如: -```swift -println(SomeClass.computedTypeProperty) -// 输出 "42" - -println(SomeStructure.storedTypeProperty) -// 输出 "Some value." +```swift +print(SomeStructure.storedTypeProperty) +// 输出 "Some value." SomeStructure.storedTypeProperty = "Another value." -println(SomeStructure.storedTypeProperty) -// 输出 "Another value.” +print(SomeStructure.storedTypeProperty) +// 输出 "Another value.” +print(SomeEnumeration.computedTypeProperty) +// 输出 "6" +print(SomeClass.computedTypeProperty) +// 输出 "27" ``` 下面的例子定义了一个结构体,使用两个存储型类型属性来表示多个声道的声音电平值,每个声道有一个 0 到 10 之间的整数表示声音电平值。 @@ -355,23 +358,23 @@ println(SomeStructure.storedTypeProperty) Static Properties VUMeter -上面所描述的声道模型使用`AudioChannel`结构体来表示: +上面所描述的声道模型使用`AudioChannel`结构体的实例来表示: ```swift struct AudioChannel { static let thresholdLevel = 10 static var maxInputLevelForAllChannels = 0 var currentLevel: Int = 0 { - didSet { - if currentLevel > AudioChannel.thresholdLevel { - // 将新电平值设置为阀值 - currentLevel = AudioChannel.thresholdLevel + didSet { + if currentLevel > AudioChannel.thresholdLevel { + // 将新电平值设置为阀值 + currentLevel = AudioChannel.thresholdLevel + } + if currentLevel > AudioChannel.maxInputLevelForAllChannels { + // 存储当前电平值作为新的最大输入电平 + AudioChannel.maxInputLevelForAllChannels = currentLevel + } } - if currentLevel > AudioChannel.maxInputLevelForAllChannels { - // 存储当前电平值作为新的最大输入电平 - AudioChannel.maxInputLevelForAllChannels = currentLevel - } - } } } ``` @@ -382,10 +385,10 @@ struct AudioChannel { `AudioChannel`也定义了一个名为`currentLevel`的实例存储属性,表示当前声道现在的电平值,取值为 0 到 10。 -属性`currentLevel`包含`didSet`属性观察器来检查每次新设置后的属性值,有如下两个检查: +属性`currentLevel`包含`didSet`属性观察器来检查每次新设置后的属性值,它有如下两个检查: - 如果`currentLevel`的新值大于允许的阈值`thresholdLevel`,属性观察器将`currentLevel`的值限定为阈值`thresholdLevel`。 -- 如果修正后的`currentLevel`值大于任何之前任意`AudioChannel`实例中的值,属性观察器将新值保存在静态属性`maxInputLevelForAllChannels`中。 +- 如果前一个修正后的`currentLevel`值大于任何之前任意`AudioChannel`实例中的值,属性观察器将新值保存在静态类型属性`maxInputLevelForAllChannels`中。 > 注意: > 在第一个检查过程中,`didSet`属性观察器将`currentLevel`设置成了不同的值,但这时不会再次调用属性观察器。 @@ -401,9 +404,9 @@ var rightChannel = AudioChannel() ```swift leftChannel.currentLevel = 7 -println(leftChannel.currentLevel) +print(leftChannel.currentLevel) // 输出 "7" -println(AudioChannel.maxInputLevelForAllChannels) +print(AudioChannel.maxInputLevelForAllChannels) // 输出 "7" ``` @@ -411,8 +414,8 @@ println(AudioChannel.maxInputLevelForAllChannels) ```swift rightChannel.currentLevel = 11 -println(rightChannel.currentLevel) +print(rightChannel.currentLevel) // 输出 "10" -println(AudioChannel.maxInputLevelForAllChannels) +print(AudioChannel.maxInputLevelForAllChannels) // 输出 "10" ``` From 5ff10629b56f82ebc8833d305fe5e648b2203e02 Mon Sep 17 00:00:00 2001 From: Siyu Yang Date: Wed, 1 Jul 2015 16:32:30 +0800 Subject: [PATCH 5/6] Chapter2_Properties Section3 minor_fix --- source/chapter2/10_Properties.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source/chapter2/10_Properties.md b/source/chapter2/10_Properties.md index 12f80f0b..3ee6921e 100755 --- a/source/chapter2/10_Properties.md +++ b/source/chapter2/10_Properties.md @@ -233,8 +233,9 @@ print("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)") 类似地,`didSet`观察器会将旧的属性值作为参数传入,可以为该参数命名或者使用默认参数名`oldValue`。 -> 注意: -> `willSet`和`didSet`观察器在属性初始化过程中不会被调用,它们只会当属性的值在初始化之外的地方被设置时被调用。 +> 注意: +> 父类的属性在子类的构造器中被赋值时,它在父类中的`willSet`和`didSet`观察器会被调用。 +> 有关构造器代理的更多信息,请参考[值类型的构造器代理](chapter/14_Initialization.html#initializer_delegation_for_value_types)和[构造器链](chapter/14_Initialization.html#initialization_chain)。 这里是一个`willSet`和`didSet`的实际例子,其中定义了一个名为`StepCounter`的类,用来统计当人步行时的总步数。这个类可以跟计步器或其他日常锻炼的统计装置的输入数据配合使用。 From 39d551ae824fa292952e8d345b1a2a11ef68d0d7 Mon Sep 17 00:00:00 2001 From: Siyu Yang Date: Wed, 1 Jul 2015 16:35:59 +0800 Subject: [PATCH 6/6] Chapter2_Type_Casting quote_format minor_fix --- source/chapter2/20_Type_Casting.md | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/source/chapter2/20_Type_Casting.md b/source/chapter2/20_Type_Casting.md index dc72a95f..83929634 100644 --- a/source/chapter2/20_Type_Casting.md +++ b/source/chapter2/20_Type_Casting.md @@ -141,9 +141,8 @@ for item in library { 若向下转型成功,然后 `movie` 的属性将用于打印一个 `Movie` 实例的描述,包括它的导演的名字 `director` 。相近的原理被用来检测 `Song` 实例,当 `Song` 被找到时则打印它的描述(包含 `artist` 的名字)。 -> 注意: - ->转换没有真的改变实例或它的值。潜在的根本的实例保持不变;只是简单地把它作为它被转换成的类来使用。 +> 注意: +> 转换没有真的改变实例或它的值。潜在的根本的实例保持不变;只是简单地把它作为它被转换成的类来使用。 ## `Any`和`AnyObject`的类型转换 @@ -153,9 +152,8 @@ Swift为不确定类型提供了两种特殊类型别名: * `AnyObject`可以代表任何class类型的实例。 * `Any`可以表示任何类型,包括方法类型(function types)。 -> 注意: - ->只有当你明确的需要它的行为和功能时才使用`Any`和`AnyObject`。在你的代码里使用你期望的明确的类型总是更好的。 +> 注意: +> 只有当你明确的需要它的行为和功能时才使用`Any`和`AnyObject`。在你的代码里使用你期望的明确的类型总是更好的。 ### `AnyObject`类型 @@ -254,6 +252,5 @@ for thing in things { ``` -> 注意: - ->在一个switch语句的case中使用强制形式的类型转换操作符(as, 而不是 as?)来检查和转换到一个明确的类型。在 `switch` case 语句的内容中这种检查总是安全的。 +> 注意: +> 在一个switch语句的case中使用强制形式的类型转换操作符(as, 而不是 as?)来检查和转换到一个明确的类型。在 `switch` case 语句的内容中这种检查总是安全的。