make gitbook
This commit is contained in:
139
chapter2/10_Properties.html
Executable file → Normal file
139
chapter2/10_Properties.html
Executable file → Normal file
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.10" data-basepath=".." data-revision="1402677669306">
|
||||
<div class="book" data-level="2.10" data-basepath=".." data-revision="1402750255397">
|
||||
<div class="book-header">
|
||||
<!-- Actions Left -->
|
||||
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
|
||||
@ -268,7 +268,7 @@
|
||||
<li class="chapter " data-level="2.12" data-path="chapter2/12_Subscripts.html">
|
||||
|
||||
<a href="../chapter2/12_Subscripts.html">
|
||||
<i class="fa fa-check"></i> <b>2.12.</b> 附属脚本
|
||||
<i class="fa fa-check"></i> <b>2.12.</b> 下标脚本
|
||||
</a>
|
||||
|
||||
|
||||
@ -520,7 +520,7 @@
|
||||
|
||||
<a href="../chapter2/11_Methods.html" title="方法" class="chapter " data-progress="2.11" style="left: 18.42105263157895%;"></a>
|
||||
|
||||
<a href="../chapter2/12_Subscripts.html" title="附属脚本" class="chapter " data-progress="2.12" style="left: 21.05263157894737%;"></a>
|
||||
<a href="../chapter2/12_Subscripts.html" title="下标脚本" class="chapter " data-progress="2.12" style="left: 21.05263157894737%;"></a>
|
||||
|
||||
<a href="../chapter2/13_Inheritance.html" title="继承" class="chapter " data-progress="2.13" style="left: 23.68421052631579%;"></a>
|
||||
|
||||
@ -587,11 +587,10 @@
|
||||
|
||||
<div class="page-inner">
|
||||
|
||||
<section class="normal" id="section-gitbook_105">
|
||||
<section class="normal" id="section-gitbook_57">
|
||||
|
||||
<blockquote>
|
||||
<p>翻译:shinyzhu</p>
|
||||
<p>校对:pp-prog</p>
|
||||
<p>翻译:shinyzhu<br>校对:pp-prog </p>
|
||||
</blockquote>
|
||||
<h1 id="-properties-">属性 (Properties)</h1>
|
||||
<hr>
|
||||
@ -610,8 +609,8 @@
|
||||
<h2 id="-">存储属性</h2>
|
||||
<p>简单来说,一个存储属性就是存储在特定类或结构体的实例里的一个常量或变量,存储属性可以是<em>变量存储属性</em>(用关键字<code>var</code>定义),也可以是<em>常量存储属性</em>(用关键字<code>let</code>定义)。</p>
|
||||
<p>可以在定义存储属性的时候指定默认值,请参考<a href="../chapter2/14_Initialization.html">构造过程</a>一章的<a href="../chapter2/14_Initialization.html#default_property_values">默认属性值</a>一节。也可以在构造过程中设置或修改存储属性的值,甚至修改常量存储属性的值,请参考<a href="../chapter2/14_Initialization.html">构造过程</a>一章的<a href="../chapter2/14_Initialization.html#modifying_constant_properties_during_initialization">在初始化阶段修改常量存储属性</a>一节。</p>
|
||||
<p>下面的例子定义了一个名为<code>FixedLengthRange</code>的结构体,他描述了一个在创建后无法修改值域宽度的区间:</p>
|
||||
<pre><code>struct FixedLengthRange {
|
||||
<p>下面的例子定义了一个名为<code>FixedLengthRange</code>的结构体,它描述了一个在创建后无法修改值域宽度的区间:</p>
|
||||
<pre><code class="lang-swift">struct FixedLengthRange {
|
||||
var firstValue: Int
|
||||
let length: Int
|
||||
}
|
||||
@ -619,27 +618,28 @@ var rangeOfThreeItems = FixedLengthRange(firstValue: 0, length: 3)
|
||||
// 该区间表示整数0,1,2
|
||||
rangeOfThreeItems.firstValue = 6
|
||||
// 该区间现在表示整数6,7,8
|
||||
</code></pre><p><code>FixedLengthRange</code>的实例包含一个名为<code>firstValue</code>的变量存储属性和一个名为<code>length</code>的常量存储属性。在上面的例子中,<code>length</code>在创建实例的时候被赋值,因为它是一个常量存储属性,所以之后无法修改它的值。</p>
|
||||
</code></pre>
|
||||
<p><code>FixedLengthRange</code>的实例包含一个名为<code>firstValue</code>的变量存储属性和一个名为<code>length</code>的常量存储属性。在上面的例子中,<code>length</code>在创建实例的时候被赋值,因为它是一个常量存储属性,所以之后无法修改它的值。</p>
|
||||
<p><a name="stored_properties_of_constant_structure_instances"></a></p>
|
||||
<h3 id="-">常量和存储属性</h3>
|
||||
<p>如果创建了一个结构体的实例并赋值给一个常量,则无法修改实例的任何属性,即使定义了变量存储属性:</p>
|
||||
<pre><code>let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4)
|
||||
<pre><code class="lang-swift">let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4)
|
||||
// 该区间表示整数0,1,2,3
|
||||
rangeOfFourItems.firstValue = 6
|
||||
// 尽管 firstValue 是个变量属性,这里还是会报错
|
||||
</code></pre><p>因为<code>rangeOfFourItems</code>声明成了常量(用<code>let</code>关键字),即使<code>firstValue</code>是一个变量属性,也无法再修改它了。</p>
|
||||
</code></pre>
|
||||
<p>因为<code>rangeOfFourItems</code>声明成了常量(用<code>let</code>关键字),即使<code>firstValue</code>是一个变量属性,也无法再修改它了。</p>
|
||||
<p>这种行为是由于结构体(struct)属于<em>值类型</em>。当值类型的实例被声明为常量的时候,它的所有属性也就成了常量。</p>
|
||||
<p>属于<em>引用类型</em>的类(class)则不一样,把一个引用类型的实例赋给一个常量后,仍然可以修改实例的变量属性。</p>
|
||||
<p><a name="lazy_stored_properties"></a></p>
|
||||
<h3 id="-">延迟存储属性</h3>
|
||||
<p>延迟存储属性是指当第一次被调用的时候才会计算其初始值的属性。在属性声明前使用<code>@lazy</code>来标示一个延迟存储属性。</p>
|
||||
<blockquote>
|
||||
<p>注意:</p>
|
||||
<p>必须将延迟存储属性声明成变量(使用<code>var</code>关键字),因为属性的值在实例构造完成之前可能无法得到。而常量属性在构造过程完成之前必须要有初始值,因此无法声明成延迟属性。</p>
|
||||
<p>注意:<br>必须将延迟存储属性声明成变量(使用<code>var</code>关键字),因为属性的值在实例构造完成之前可能无法得到。而常量属性在构造过程完成之前必须要有初始值,因此无法声明成延迟属性。 </p>
|
||||
</blockquote>
|
||||
<p>延迟属性很有用,当属性的值依赖于在实例的构造过程结束前无法知道具体值的外部因素时,或者当属性的值需要复杂或大量计算时,可以只在需要的时候来计算它。</p>
|
||||
<p>下面的例子使用了延迟存储属性来避免复杂类的不必要的初始化。例子中定义了<code>DataImporter</code>和<code>DataManager</code>两个类,下面是部分代码:</p>
|
||||
<pre><code>class DataImporter {
|
||||
<pre><code class="lang-swift">class DataImporter {
|
||||
/*
|
||||
DataImporter 是一个将外部文件中的数据导入的类。
|
||||
这个类的初始化会消耗不少时间。
|
||||
@ -658,14 +658,16 @@ let manager = DataManager()
|
||||
manager.data += "Some data"
|
||||
manager.data += "Some more data"
|
||||
// DataImporter 实例的 importer 属性还没有被创建
|
||||
</code></pre><p><code>DataManager</code>类包含一个名为<code>data</code>的存储属性,初始值是一个空的字符串(<code>String</code>)数组。虽然没有写出全部代码,<code>DataManager</code>类的目的是管理和提供对这个字符串数组的访问。</p>
|
||||
</code></pre>
|
||||
<p><code>DataManager</code>类包含一个名为<code>data</code>的存储属性,初始值是一个空的字符串(<code>String</code>)数组。虽然没有写出全部代码,<code>DataManager</code>类的目的是管理和提供对这个字符串数组的访问。</p>
|
||||
<p><code>DataManager</code>的一个功能是从文件导入数据,该功能由<code>DataImporter</code>类提供,<code>DataImporter</code>需要消耗不少时间完成初始化:因为它的实例在初始化时可能要打开文件,还要读取文件内容到内存。</p>
|
||||
<p><code>DataManager</code>也可能不从文件中导入数据。所以当<code>DataManager</code>的实例被创建时,没必要创建一个<code>DataImporter</code>的实例,更明智的是当用到<code>DataImporter</code>的时候才去创建它。</p>
|
||||
<p>由于使用了<code>@lazy</code>,<code>importer</code>属性只有在第一次被访问的时候才被创建。比如访问它的属性<code>fileName</code>时:</p>
|
||||
<pre><code>println(manager.importer.fileName)
|
||||
<pre><code class="lang-swift">println(manager.importer.fileName)
|
||||
// DataImporter 实例的 importer 属性现在被创建了
|
||||
// 输出 "data.txt”
|
||||
</code></pre><p><a name="stored_properties_and_instance_variables"></a></p>
|
||||
</code></pre>
|
||||
<p><a name="stored_properties_and_instance_variables"></a></p>
|
||||
<h3 id="-">存储属性和实例变量</h3>
|
||||
<p>如果您有过 Objective-C 经验,应该知道有两种方式在类实例存储值和引用。对于属性来说,也可以使用实例变量作为属性值的后端存储。</p>
|
||||
<p>Swift 编程语言中把这些理论统一用属性来实现。Swift 中的属性没有对应的实例变量,属性的后端存储也无法直接访问。这就避免了不同场景下访问方式的困扰,同时也将属性的定义简化成一个语句。
|
||||
@ -673,7 +675,7 @@ manager.data += "Some more data"
|
||||
<p><a name="computed_properties"></a></p>
|
||||
<h2 id="-">计算属性</h2>
|
||||
<p>除存储属性外,类、结构体和枚举可以定义<em>计算属性</em>,计算属性不直接存储值,而是提供一个 getter 来获取值,一个可选的 setter 来间接设置其他属性或变量的值。</p>
|
||||
<pre><code>struct Point {
|
||||
<pre><code class="lang-swift">struct Point {
|
||||
var x = 0.0, y = 0.0
|
||||
}
|
||||
struct Size {
|
||||
@ -700,7 +702,8 @@ 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))")
|
||||
// 输出 "square.origin is now at (10.0, 10.0)”
|
||||
</code></pre><p>这个例子定义了 3 个几何形状的结构体:</p>
|
||||
</code></pre>
|
||||
<p>这个例子定义了 3 个几何形状的结构体:</p>
|
||||
<ul>
|
||||
<li><code>Point</code>封装了一个<code>(x, y)</code>的坐标</li>
|
||||
<li><code>Size</code>封装了一个<code>width</code>和<code>height</code></li>
|
||||
@ -714,7 +717,7 @@ println("square.origin is now at (\(square.origin.x), \(square.origin.y))&q
|
||||
<p><a name="shorthand_setter_declaration"></a></p>
|
||||
<h3 id="-setter-">便捷 setter 声明</h3>
|
||||
<p>如果计算属性的 setter 没有定义表示新值的参数名,则可以使用默认名称<code>newValue</code>。下面是使用了便捷 setter 声明的<code>Rect</code>结构体代码:</p>
|
||||
<pre><code>struct AlternativeRect {
|
||||
<pre><code class="lang-swift">struct AlternativeRect {
|
||||
var origin = Point()
|
||||
var size = Size()
|
||||
var center: Point {
|
||||
@ -729,15 +732,32 @@ println("square.origin is now at (\(square.origin.x), \(square.origin.y))&q
|
||||
}
|
||||
}
|
||||
}
|
||||
</code></pre><p><a name="readonly_computed_properties"></a></p>
|
||||
</code></pre>
|
||||
<p><a name="readonly_computed_properties"></a></p>
|
||||
<h3 id="-">只读计算属性</h3>
|
||||
<p>只有 getter 没有 setter 的计算属性就是<em>只读计算属性</em>。只读计算属性总是返回一个值,可以通过点运算符访问,但不能设置新的值。</p>
|
||||
<p><<<<<<< HEAD</p>
|
||||
<blockquote>
|
||||
<p>注意: </p>
|
||||
<h1 id="-var-let-">必须使用<code>var</code>关键字定义计算属性,包括只读计算属性,因为他们的值不是固定的。<code>let</code>关键字只用来声明常量属性,表示初始化后再也无法修改的值。 </h1>
|
||||
<p>注意:</p>
|
||||
<p>必须使用<code>var</code>关键字定义计算属性,包括只读计算属性,因为他们的值不是固定的。<code>let</code>关键字只用来声明常量属性,表示初始化后再也无法修改的值。</p>
|
||||
<p>必须使用<code>var</code>关键字定义计算属性,包括只读计算属性,因为它们的值不是固定的。<code>let</code>关键字只用来声明常量属性,表示初始化后再也无法修改的值。</p>
|
||||
<blockquote>
|
||||
<blockquote>
|
||||
<blockquote>
|
||||
<blockquote>
|
||||
<blockquote>
|
||||
<blockquote>
|
||||
<p>a516af6a531a104ec88da0d236ecf389a5ec72af</p>
|
||||
</blockquote>
|
||||
</blockquote>
|
||||
</blockquote>
|
||||
</blockquote>
|
||||
</blockquote>
|
||||
</blockquote>
|
||||
</blockquote>
|
||||
<p>只读计算属性的声明可以去掉<code>get</code>关键字和花括号:</p>
|
||||
<pre><code>struct Cuboid {
|
||||
<pre><code class="lang-swift">struct Cuboid {
|
||||
var width = 0.0, height = 0.0, depth = 0.0
|
||||
var volume: Double {
|
||||
return width * height * depth
|
||||
@ -746,14 +766,14 @@ println("square.origin is now at (\(square.origin.x), \(square.origin.y))&q
|
||||
let fourByFiveByTwo = Cuboid(width: 4.0, height: 5.0, depth: 2.0)
|
||||
println("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)")
|
||||
// 输出 "the volume of fourByFiveByTwo is 40.0"
|
||||
</code></pre><p>这个例子定义了一个名为<code>Cuboid</code>的结构体,表示三维空间的立方体,包含<code>width</code>、<code>height</code>和<code>depth</code>属性,还有一个名为<code>volume</code>的只读计算属性用来返回立方体的体积。设置<code>volume</code>的值毫无意义,因为通过<code>width</code>、<code>height</code>和<code>depth</code>就能算出<code>volume</code>。然而,<code>Cuboid</code>提供一个只读计算属性来让外部用户直接获取体积是很有用的。</p>
|
||||
</code></pre>
|
||||
<p>这个例子定义了一个名为<code>Cuboid</code>的结构体,表示三维空间的立方体,包含<code>width</code>、<code>height</code>和<code>depth</code>属性,还有一个名为<code>volume</code>的只读计算属性用来返回立方体的体积。设置<code>volume</code>的值毫无意义,因为通过<code>width</code>、<code>height</code>和<code>depth</code>就能算出<code>volume</code>。然而,<code>Cuboid</code>提供一个只读计算属性来让外部用户直接获取体积是很有用的。</p>
|
||||
<p><a name="property_observers"></a></p>
|
||||
<h2 id="-">属性监视器</h2>
|
||||
<p><em>属性监视器</em>监控和响应属性值的变化,每次属性被设置值的时候都会调用属性监视器,甚至新的值和现在的值相同的时候也不例外。</p>
|
||||
<p>可以为除了延迟存储属性之外的其他存储属性添加属性监视器,也可以通过重载属性的方式为继承的属性(包括存储属性和计算属性)添加属性监视器。属性重载请参考<a href="chapter/13_Inheritance.html">继承</a>一章的<a href="chapter/13_Inheritance.html#overriding">重载</a>。</p>
|
||||
<blockquote>
|
||||
<p>注意:</p>
|
||||
<p>不需要为无法重载的计算属性添加属性监视器,因为可以通过 setter 直接监控和响应值的变化。</p>
|
||||
<p>注意:<br>不需要为无法重载的计算属性添加属性监视器,因为可以通过 setter 直接监控和响应值的变化。 </p>
|
||||
</blockquote>
|
||||
<p>可以为属性添加如下的一个或全部监视器:</p>
|
||||
<ul>
|
||||
@ -762,12 +782,28 @@ println("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)")
|
||||
</ul>
|
||||
<p><code>willSet</code>监视器会将新的属性值作为固定参数传入,在<code>willSet</code>的实现代码中可以为这个参数指定一个名称,如果不指定则参数仍然可用,这时使用默认名称<code>newValue</code>表示。</p>
|
||||
<p>类似地,<code>didSet</code>监视器会将旧的属性值作为参数传入,可以为该参数命名或者使用默认参数名<code>oldValue</code>。</p>
|
||||
<p><<<<<<< HEAD</p>
|
||||
<blockquote>
|
||||
<p>注意: </p>
|
||||
<h1 id="-willset-didset-"><code>willSet</code>和<code>didSet</code>监视器在属性初始化过程中不会被调用,他们只会当属性的值在初始化之外的地方被设置时被调用。 </h1>
|
||||
<p>注意:</p>
|
||||
<p><code>willSet</code>和<code>didSet</code>监视器在属性初始化过程中不会被调用,他们只会当属性的值在初始化之外的地方被设置时被调用。</p>
|
||||
<p><code>willSet</code>和<code>didSet</code>监视器在属性初始化过程中不会被调用,它们只会当属性的值在初始化之外的地方被设置时被调用。</p>
|
||||
<blockquote>
|
||||
<blockquote>
|
||||
<blockquote>
|
||||
<blockquote>
|
||||
<blockquote>
|
||||
<blockquote>
|
||||
<p>a516af6a531a104ec88da0d236ecf389a5ec72af</p>
|
||||
</blockquote>
|
||||
</blockquote>
|
||||
</blockquote>
|
||||
</blockquote>
|
||||
</blockquote>
|
||||
</blockquote>
|
||||
</blockquote>
|
||||
<p>这里是一个<code>willSet</code>和<code>didSet</code>的实际例子,其中定义了一个名为<code>StepCounter</code>的类,用来统计当人步行时的总步数,可以跟计步器或其他日常锻炼的统计装置的输入数据配合使用。</p>
|
||||
<pre><code>class StepCounter {
|
||||
<pre><code class="lang-swift">class StepCounter {
|
||||
var totalSteps: Int = 0 {
|
||||
willSet(newTotalSteps) {
|
||||
println("About to set totalSteps to \(newTotalSteps)")
|
||||
@ -789,13 +825,13 @@ stepCounter.totalSteps = 360
|
||||
stepCounter.totalSteps = 896
|
||||
// About to set totalSteps to 896
|
||||
// Added 536 steps
|
||||
</code></pre><p><code>StepCounter</code>类定义了一个<code>Int</code>类型的属性<code>totalSteps</code>,它是一个存储属性,包含<code>willSet</code>和<code>didSet</code>监视器。</p>
|
||||
</code></pre>
|
||||
<p><code>StepCounter</code>类定义了一个<code>Int</code>类型的属性<code>totalSteps</code>,它是一个存储属性,包含<code>willSet</code>和<code>didSet</code>监视器。</p>
|
||||
<p>当<code>totalSteps</code>设置新值的时候,它的<code>willSet</code>和<code>didSet</code>监视器都会被调用,甚至当新的值和现在的值完全相同也会调用。</p>
|
||||
<p>例子中的<code>willSet</code>监视器将表示新值的参数自定义为<code>newTotalSteps</code>,这个监视器只是简单的将新的值输出。</p>
|
||||
<p><code>didSet</code>监视器在<code>totalSteps</code>的值改变后被调用,它把新的值和旧的值进行对比,如果总的步数增加了,就输出一个消息表示增加了多少步。<code>didSet</code>没有提供自定义名称,所以默认值<code>oldValue</code>表示旧值的参数名。</p>
|
||||
<blockquote>
|
||||
<p>注意:</p>
|
||||
<p>如果在<code>didSet</code>监视器里为属性赋值,这个值会替换监视器之前设置的值。</p>
|
||||
<p>注意:<br>如果在<code>didSet</code>监视器里为属性赋值,这个值会替换监视器之前设置的值。 </p>
|
||||
</blockquote>
|
||||
<p><a name="global_and_local_variables"></a></p>
|
||||
<h2 id="-">全局变量和局部变量</h2>
|
||||
@ -803,9 +839,7 @@ stepCounter.totalSteps = 896
|
||||
<p>前面章节提到的全局或局部变量都属于存储型变量,跟存储属性类似,它提供特定类型的存储空间,并允许读取和写入。</p>
|
||||
<p>另外,在全局或局部范围都可以定义计算型变量和为存储型变量定义监视器,计算型变量跟计算属性一样,返回一个计算的值而不是存储值,声明格式也完全一样。</p>
|
||||
<blockquote>
|
||||
<p>注意:</p>
|
||||
<p>全局的常量或变量都是延迟计算的,跟<a href="#lazy_stored_properties">延迟存储属性</a>相似,不同的地方在于,全局的常量或变量不需要标记<code>@lazy</code>特性。</p>
|
||||
<p>局部范围的常量或变量不会延迟计算。</p>
|
||||
<p>注意:<br>全局的常量或变量都是延迟计算的,跟<a href="#lazy_stored_properties">延迟存储属性</a>相似,不同的地方在于,全局的常量或变量不需要标记<code>@lazy</code>特性。<br>局部范围的常量或变量不会延迟计算。 </p>
|
||||
</blockquote>
|
||||
<p><a name="type_properties"></a></p>
|
||||
<h2 id="-">类型属性</h2>
|
||||
@ -815,14 +849,13 @@ stepCounter.totalSteps = 896
|
||||
<p>对于值类型(指结构体和枚举)可以定义存储型和计算型类型属性,对于类(class)则只能定义计算型类型属性。</p>
|
||||
<p>值类型的存储型类型属性可以是变量或常量,计算型类型属性跟实例的计算属性一样定义成变量属性。</p>
|
||||
<blockquote>
|
||||
<p>注意:</p>
|
||||
<p>跟实例的存储属性不同,必须给存储型类型属性指定默认值,因为类型本身无法在初始化过程中使用构造器给类型属性赋值。</p>
|
||||
<p>注意:<br>跟实例的存储属性不同,必须给存储型类型属性指定默认值,因为类型本身无法在初始化过程中使用构造器给类型属性赋值。 </p>
|
||||
</blockquote>
|
||||
<p><a name="type_property_syntax"></a></p>
|
||||
<h3 id="-">类型属性语法</h3>
|
||||
<p>在 C 或 Objective-C 中,静态常量和静态变量的定义是通过特定类型加上<code>global</code>关键字。在 Swift 编程语言中,类型属性是作为类型定义的一部分写在类型最外层的花括号内,因此它的作用范围也就在类型支持的范围内。</p>
|
||||
<p>使用关键字<code>static</code>来定义值类型的类型属性,关键字<code>class</code>来为类(class)定义类型属性。下面的例子演示了存储型和计算型类型属性的语法:</p>
|
||||
<pre><code>struct SomeStructure {
|
||||
<pre><code class="lang-swift">struct SomeStructure {
|
||||
static var storedTypeProperty = "Some value."
|
||||
static var computedTypeProperty: Int {
|
||||
// 这里返回一个 Int 值
|
||||
@ -839,14 +872,14 @@ class SomeClass {
|
||||
// 这里返回一个 Int 值
|
||||
}
|
||||
}
|
||||
</code></pre><blockquote>
|
||||
<p>注意:</p>
|
||||
<p>例子中的计算型类型属性是只读的,但也可以定义可读可写的计算型类型属性,跟实例计算属性的语法类似。</p>
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>注意:<br>例子中的计算型类型属性是只读的,但也可以定义可读可写的计算型类型属性,跟实例计算属性的语法类似。 </p>
|
||||
</blockquote>
|
||||
<p><a name="querying_and_setting_type_properties"></a></p>
|
||||
<h3 id="-">获取和设置类型属性的值</h3>
|
||||
<p>跟实例的属性一样,类型属性的访问也是通过点运算符来进行,但是,类型属性是通过类型本身来获取和设置,而不是通过实例。比如:</p>
|
||||
<pre><code>println(SomeClass.computedTypeProperty)
|
||||
<pre><code class="lang-swift">println(SomeClass.computedTypeProperty)
|
||||
// 输出 "42"
|
||||
|
||||
println(SomeStructure.storedTypeProperty)
|
||||
@ -854,11 +887,12 @@ println(SomeStructure.storedTypeProperty)
|
||||
SomeStructure.storedTypeProperty = "Another value."
|
||||
println(SomeStructure.storedTypeProperty)
|
||||
// 输出 "Another value.”
|
||||
</code></pre><p>下面的例子定义了一个结构体,使用两个存储型类型属性来表示多个声道的声音电平值,每个声道有一个 0 到 10 之间的整数表示声音电平值。</p>
|
||||
</code></pre>
|
||||
<p>下面的例子定义了一个结构体,使用两个存储型类型属性来表示多个声道的声音电平值,每个声道有一个 0 到 10 之间的整数表示声音电平值。</p>
|
||||
<p>后面的图表展示了如何联合使用两个声道来表示一个立体声的声音电平值。当声道的电平值是 0,没有一个灯会亮;当声道的电平值是 10,所有灯点亮。本图中,左声道的电平是 9,右声道的电平是 7。</p>
|
||||
<p><img src="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/staticPropertiesVUMeter_2x.png" alt="Static Properties VUMeter" width="243" height="357" /></p>
|
||||
<p>上面所描述的声道模型使用<code>AudioChannel</code>结构体来表示:</p>
|
||||
<pre><code>struct AudioChannel {
|
||||
<pre><code class="lang-swift">struct AudioChannel {
|
||||
static let thresholdLevel = 10
|
||||
static var maxInputLevelForAllChannels = 0
|
||||
var currentLevel: Int = 0 {
|
||||
@ -874,7 +908,8 @@ println(SomeStructure.storedTypeProperty)
|
||||
}
|
||||
}
|
||||
}
|
||||
</code></pre><p>结构<code>AudioChannel</code>定义了 2 个存储型类型属性来实现上述功能。第一个是<code>thresholdLevel</code>,表示声音电平的最大上限阈值,它是一个取值为 10 的常量,对所有实例都可见,如果声音电平高于 10,则取最大上限值 10(见后面描述)。</p>
|
||||
</code></pre>
|
||||
<p>结构<code>AudioChannel</code>定义了 2 个存储型类型属性来实现上述功能。第一个是<code>thresholdLevel</code>,表示声音电平的最大上限阈值,它是一个取值为 10 的常量,对所有实例都可见,如果声音电平高于 10,则取最大上限值 10(见后面描述)。</p>
|
||||
<p>第二个类型属性是变量存储型属性<code>maxInputLevelForAllChannels</code>,它用来表示所有<code>AudioChannel</code>实例的电平值的最大值,初始值是 0。</p>
|
||||
<p><code>AudioChannel</code>也定义了一个名为<code>currentLevel</code>的实例存储属性,表示当前声道现在的电平值,取值为 0 到 10。</p>
|
||||
<p>属性<code>currentLevel</code>包含<code>didSet</code>属性监视器来检查每次新设置后的属性值,有如下两个检查:</p>
|
||||
@ -883,25 +918,27 @@ println(SomeStructure.storedTypeProperty)
|
||||
<li>如果修正后的<code>currentLevel</code>值大于任何之前任意<code>AudioChannel</code>实例中的值,属性监视器将新值保存在静态属性<code>maxInputLevelForAllChannels</code>中。</li>
|
||||
</ul>
|
||||
<blockquote>
|
||||
<p>注意:</p>
|
||||
<p>在第一个检查过程中,<code>didSet</code>属性监视器将<code>currentLevel</code>设置成了不同的值,但这时不会再次调用属性监视器。</p>
|
||||
<p>注意:<br>在第一个检查过程中,<code>didSet</code>属性监视器将<code>currentLevel</code>设置成了不同的值,但这时不会再次调用属性监视器。 </p>
|
||||
</blockquote>
|
||||
<p>可以使用结构体<code>AudioChannel</code>来创建表示立体声系统的两个声道<code>leftChannel</code>和<code>rightChannel</code>:</p>
|
||||
<pre><code>var leftChannel = AudioChannel()
|
||||
<pre><code class="lang-swift">var leftChannel = AudioChannel()
|
||||
var rightChannel = AudioChannel()
|
||||
</code></pre><p>如果将左声道的电平设置成 7,类型属性<code>maxInputLevelForAllChannels</code>也会更新成 7:</p>
|
||||
<pre><code>leftChannel.currentLevel = 7
|
||||
</code></pre>
|
||||
<p>如果将左声道的电平设置成 7,类型属性<code>maxInputLevelForAllChannels</code>也会更新成 7:</p>
|
||||
<pre><code class="lang-swift">leftChannel.currentLevel = 7
|
||||
println(leftChannel.currentLevel)
|
||||
// 输出 "7"
|
||||
println(AudioChannel.maxInputLevelForAllChannels)
|
||||
// 输出 "7"
|
||||
</code></pre><p>如果试图将右声道的电平设置成 11,则会将右声道的<code>currentLevel</code>修正到最大值 10,同时<code>maxInputLevelForAllChannels</code>的值也会更新到 10:</p>
|
||||
<pre><code>rightChannel.currentLevel = 11
|
||||
</code></pre>
|
||||
<p>如果试图将右声道的电平设置成 11,则会将右声道的<code>currentLevel</code>修正到最大值 10,同时<code>maxInputLevelForAllChannels</code>的值也会更新到 10:</p>
|
||||
<pre><code class="lang-swift">rightChannel.currentLevel = 11
|
||||
println(rightChannel.currentLevel)
|
||||
// 输出 "10"
|
||||
println(AudioChannel.maxInputLevelForAllChannels)
|
||||
// 输出 "10"
|
||||
</code></pre>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user