Swift语法全面解析
<h3 id="swift介绍">Swift介绍</h3>
<p>Swift 是一门开发 iOS, macOS, watchOS 和 tvOS 应用的新语言。
swift 是一种安全,快速和互动的编程语言。
swift 支持代码预览(playgrounds),这个特性可以允许程序员在不编译和运行应用程序的前提下运行 Swift 代码并实时查看结果。</p>
<p>Swift 通过采用现代编程模式来避免大量常见编程错误:</p>
<ul>
<li>变量始终在使用前初始化。</li>
<li>检查数组索引超出范围的错误。</li>
<li>检查整数是否溢出。</li>
<li>可选值确保明确处理 nil 值。</li>
<li>内存被自动管理。</li>
<li>错误处理允许从意外故障控制恢复。</li>
</ul>
<h3 id="基础部分">基础部分</h3>
<h4 id="常量和变量">常量和变量</h4>
<p>声明常量和变量, 常量和变量必须在使用前声明,使用 let 来声明常量,使用 var 来声明变量。
示例:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span><span style="color:#66d9ef">let</span> maximumNumberOfLoginAttempts = <span style="color:#ae81ff">10</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">var</span> currentLoginAttempt = <span style="color:#ae81ff">0</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 类型注解</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">var</span> welcomeMessage: String
</span></span></code></pre></div><h4 id="注释">注释</h4>
<p>单行注释双正斜杠(//), 多行注释(/* 多行的 */)。Swift 的多行注释可以嵌套在其它的多行注释之中。
示例:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span><span style="color:#75715e">// 这是一个注释</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">/* 这也是一个注释,
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">但是是多行的 */</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">/* 这是第一个多行注释的开头
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">/* 这是第二个被嵌套的多行注释 */
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">这是第一个多行注释的结尾 */</span>
</span></span></code></pre></div><h4 id="分号">分号</h4>
<p>Swift 并不强制要求你在每条语句的结尾处使用分号(;)。
同一行内写多条独立的语句必须用分号分隔。</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span><span style="color:#66d9ef">let</span> cat = <span style="color:#e6db74">"🐱"</span>; print(cat)
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 输出“🐱”</span>
</span></span></code></pre></div><h4 id="标识符">标识符</h4>
<p>标识符就是给变量、常量、方法、函数、枚举、结构体、类、协议等指定的名字。构成标识符的字母均有一定的规范,Swift语言中标识符的命名规则如下:</p>
<ul>
<li>
<p>区分大小写,Myname与myname是两个不同的标识符;</p>
</li>
<li>
<p>标识符首字符可以以下划线(_)或者字母开始,但不能是数字;</p>
</li>
<li>
<p>标识符中其他字符可以是下划线(_)、字母或数字。</p>
</li>
</ul>
<p>例如: userName、User_Name、_sys_val、身高等为合法的标识符,而2mail、room#和class为非法的标识符。</p>
<p>注意:Swift中的字母采用的是Unicode编码。Unicode叫做统一编码制,它包含了亚洲文字编码,如中文、日文、韩文等字符,甚至是我们在聊天工具中使用的表情符号</p>
<p>如果一定要使用关键字作为标识符,可以在关键字前后添加重音符号(`),例如:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span><span style="color:#66d9ef">let</span> `<span style="color:#66d9ef">class</span>` = <span style="color:#e6db74">"xiaobai"</span>
</span></span></code></pre></div><h4 id="关键字">关键字</h4>
<p>关键字是类似于标识符的保留字符序列,除非用重音符号(`)将其括起来,否则不能用作标识符。关键字是对编译器具有特殊意义的预定义保留标识符。常见的关键字有以下4种。
<strong>与声明有关的关键字</strong></p>
<pre><code>class deinit enum extension
func import init internal
let operator private protocol
public static struct subscript
typealias var
</code></pre>
<p><strong>与语句有关的关键字</strong></p>
<pre><code>break case continue default
do else fallthrough for
if in return switch
where while
</code></pre>
<p><strong>表达式和类型关键字</strong></p>
<pre><code>as dynamicType false is
nil self Self super
true _COLUMN_ _FILE_ _FUNCTION_
_LINE_
</code></pre>
<p><strong>在特定上下文中使用的关键字</strong></p>
<pre><code>associativity convenience dynamic didSet
final get infix inout
lazy left mutating none
nonmutating optional override postfix
precedence prefix Protocol required
right set Type unowned
weak willSet
</code></pre>
<h4 id="swift-空格">Swift 空格</h4>
<p>Swift对空格的使用有一定的要求。
在Swift中,运算符不能直接跟在变量或常量的后面。例如下面的代码会报错:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span><span style="color:#66d9ef">let</span> a= <span style="color:#ae81ff">1</span> <span style="color:#f92672">+</span> <span style="color:#ae81ff">2</span>
</span></span></code></pre></div><p>错误信息是:</p>
<p><code>error: prefix/postfix '=' is reserved</code></p>
<p>意思大概是等号直接跟在前面或后面这种用法是保留的。</p>
<p>下面的代码还是会报错(继续注意空格):</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span><span style="color:#66d9ef">let</span> a = <span style="color:#ae81ff">1</span><span style="color:#f92672">+</span> <span style="color:#ae81ff">2</span>
</span></span></code></pre></div><p>错误信息是:</p>
<p><code>error: consecutive statements on a line must be separated by ';'</code></p>
<p>这是因为Swift认为到1+这个语句就结束了,2就是下一个语句了。</p>
<p>只有这样写才不会报错:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span><span style="color:#66d9ef">let</span> a = <span style="color:#ae81ff">1</span> <span style="color:#f92672">+</span> <span style="color:#ae81ff">2</span>; <span style="color:#75715e">// 编码规范推荐使用这种写法</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">let</span> b = <span style="color:#ae81ff">3</span><span style="color:#f92672">+</span><span style="color:#ae81ff">4</span> <span style="color:#75715e">// 这样也是OK的</span>
</span></span></code></pre></div><h4 id="整数浮点数">整数、浮点数</h4>
<p>统一使用 Int 可以提高代码的可复用性,避免不同类型数字之间的转换, 并且匹配数字的类型推断。
示例:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span><span style="color:#66d9ef">let</span> minValue = UInt8.min <span style="color:#75715e">// minValue 为 0,是 UInt8 类型</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">let</span> maxValue = UInt8.max <span style="color:#75715e">// maxValue 为 255,是 UInt8 类型</span>
</span></span></code></pre></div><h4 id="类型安全和类型推断">类型安全和类型推断</h4>
<p>Swift 是一门类型安全的语言,这意味着 Swift 可以让你清楚地知道值的类型。
如果你没有显式指定类型,Swift 会使用类型推断来选择合适的类型。(int、double)。
示例:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span><span style="color:#66d9ef">let</span> meaningOfLife = <span style="color:#ae81ff">42</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// meaningOfLife 会被推测为 Int 类型</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">let</span> pi = <span style="color:#ae81ff">3.14159</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// pi 会被推测为 Double 类型</span>
</span></span></code></pre></div><h4 id="数值型字面量数值型类型转换">数值型字面量、数值型类型转换</h4>
<p>示例:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span><span style="color:#66d9ef">let</span> decimalInteger = <span style="color:#ae81ff">17</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">let</span> binaryInteger = <span style="color:#ae81ff">0b10001</span> <span style="color:#75715e">// 二进制的17</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">let</span> octalInteger = <span style="color:#ae81ff">0o21</span> <span style="color:#75715e">// 八进制的17</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">let</span> hexadecimalInteger = <span style="color:#ae81ff">0x11</span> <span style="color:#75715e">// 十六进制的17</span>
</span></span></code></pre></div><h4 id="类型别名">类型别名</h4>
<p>类型别名(type aliases)就是给现有类型定义另一个名字。你可以使用 typealias 关键字来定义类型别名。
示例:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span><span style="color:#66d9ef">typealias</span> AudioSample = UInt16
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">var</span> maxAmplitudeFound = AudioSample.min
</span></span><span style="display:flex;"><span><span style="color:#75715e">// maxAmplitudeFound 现在是 0</span>
</span></span></code></pre></div><h4 id="布尔值">布尔值</h4>
<p>示例:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span><span style="color:#66d9ef">let</span> orangesAreOrange = <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">let</span> turnipsAreDelicious = <span style="color:#66d9ef">false</span>
</span></span></code></pre></div><h4 id="元组">元组</h4>
<p>元组(tuples)把多个值组合成一个复合值。元组内的值可以是任意类型,并不要求是相同类型。
示例:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span><span style="color:#66d9ef">let</span> http404Error = (<span style="color:#ae81ff">404</span>, <span style="color:#e6db74">"Not Found"</span>)
</span></span><span style="display:flex;"><span><span style="color:#75715e">// http404Error 的类型是 (Int, String),值是 (404, "Not Found")</span>
</span></span></code></pre></div><h4 id="可选类型">可选类型</h4>
<p>使用可选类型(optionals)来处理值可能缺失的情况。可选类型表示两种可能:或者有值, 你可以解析可选类型访问这个值, 或者根本没有值。
示例:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span><span style="color:#66d9ef">var</span> serverResponseCode: Int? = <span style="color:#ae81ff">404</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// serverResponseCode 包含一个可选的 Int 值 404</span>
</span></span><span style="display:flex;"><span>serverResponseCode = <span style="color:#66d9ef">nil</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// serverResponseCode 现在不包含值</span>
</span></span></code></pre></div><h4 id="错误处理">错误处理</h4>
<p>错误处理,应对程序执行中可能会遇到的错误条件。
示例:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">makeASandwich</span>() <span style="color:#66d9ef">throws</span> {
</span></span><span style="display:flex;"><span> <span style="color:#75715e">// ...</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">do</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">try</span> makeASandwich()
</span></span><span style="display:flex;"><span> eatASandwich()
</span></span><span style="display:flex;"><span>} <span style="color:#66d9ef">catch</span> SandwichError.outOfCleanDishes {
</span></span><span style="display:flex;"><span> washDishes()
</span></span><span style="display:flex;"><span>} <span style="color:#66d9ef">catch</span> SandwichError.missingIngredients(<span style="color:#66d9ef">let</span> ingredients) {
</span></span><span style="display:flex;"><span> buyGroceries(ingredients)
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><h4 id="断言和先决条件">断言和先决条件</h4>
<p>断言和先决条件,是在运行时所做的检查。</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span><span style="color:#66d9ef">let</span> age = <span style="color:#f92672">-</span><span style="color:#ae81ff">3</span>
</span></span><span style="display:flex;"><span>assert(age <span style="color:#f92672">>=</span> <span style="color:#ae81ff">0</span>, <span style="color:#e6db74">"A person's age cannot be less than zero"</span>)
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 因为 age < 0,所以断言会触发</span>
</span></span></code></pre></div><h4 id="基本运算符">基本运算符</h4>
<p><code>Swift 支持大部分标准 C 语言的运算符,还提供了 C 语言没有的区间运算符,例如 a..<b 或 a...b。</code>
<strong>赋值运算符,算术运算符,组合赋值运算符,比较运算符,三元运算符,空合运算符,区间运算符,逻辑运算符</strong></p>
<p>运算符分为一元、二元和三元运算符。
闭区间运算符(a…b)定义一个包含从 a 到 b(包括 a 和 b)的所有值的区间。
半开区间运算符(a..<b)定义一个从 a 到 b 但不包括 b 的区间。
闭区间操作符有另一个表达形式,可以表达往一侧无限延伸的区间,(a…,…b)。
示例:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span><span style="color:#66d9ef">let</span> names = [<span style="color:#e6db74">"Anna"</span>, <span style="color:#e6db74">"Alex"</span>, <span style="color:#e6db74">"Brian"</span>, <span style="color:#e6db74">"Jack"</span>]
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">let</span> count = names.count
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">for</span> i <span style="color:#66d9ef">in</span> <span style="color:#ae81ff">0.</span>.<count {
</span></span><span style="display:flex;"><span> print(<span style="color:#e6db74">"第 </span><span style="color:#e6db74">\(</span>i <span style="color:#f92672">+</span> <span style="color:#ae81ff">1</span><span style="color:#e6db74">)</span><span style="color:#e6db74"> 个人叫 </span><span style="color:#e6db74">\(</span>names[i]<span style="color:#e6db74">)</span><span style="color:#e6db74">"</span>)
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 第 1 个人叫 Anna</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 第 2 个人叫 Alex</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 第 3 个人叫 Brian</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 第 4 个人叫 Jack</span>
</span></span></code></pre></div><h4 id="字符串和字符">字符串和字符</h4>
<p><strong>字符串字面量,字符串插值,计算字符数量,访问和修改字符串,子字符串,比较字符串</strong></p>
<p>初始化空字符串,字符串可变性,字符串是值类型,连接字符串和字符(+,+=)。
使用字符,可通过 for-in 循环来遍历字符串,获取字符串中每一个字符的值。
字符串插值是一种构建新字符串的方式,可以在其中包含常量、变量、字面量和表达式。可以在已有字符串中插入常量、变量、字面量和表达式从而形成更长的字符串。
Swift 提供了三种方式来比较文本值:字符串字符相等、前缀相等和后缀相等。
示例:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span><span style="color:#75715e">// 多行字符串字面量</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">let</span> quotation = <span style="color:#e6db74">"""
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">The White Rabbit put on his spectacles. "</span>Where shall I begin,
</span></span><span style="display:flex;"><span>please your Majesty?<span style="color:#e6db74">" he asked.
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">"</span>Begin at the beginning,<span style="color:#e6db74">" the King said gravely, "</span>and go on
</span></span><span style="display:flex;"><span>till you come to the end; then stop.<span style="color:#e6db74">"
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">"""</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 下面两个字符串其实是一样的</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">let</span> singleLineString = <span style="color:#e6db74">"These are the same."</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">let</span> multilineString = <span style="color:#e6db74">"""
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">These are the same.
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">"""</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 字符串插值</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">let</span> multiplier = <span style="color:#ae81ff">3</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">let</span> message = <span style="color:#e6db74">"</span><span style="color:#e6db74">\(</span>multiplier<span style="color:#e6db74">)</span><span style="color:#e6db74"> times 2.5 is </span><span style="color:#e6db74">\(</span>Double<span style="color:#e6db74">(</span>multiplier<span style="color:#e6db74">)</span> <span style="color:#f92672">*</span> <span style="color:#ae81ff">2.5</span><span style="color:#e6db74">)</span><span style="color:#e6db74">"</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// message 是 "3 times 2.5 is 7.5"</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 计算字符数量</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">var</span> word = <span style="color:#e6db74">"cafe"</span>
</span></span><span style="display:flex;"><span>print(<span style="color:#e6db74">"the number of characters in </span><span style="color:#e6db74">\(</span>word<span style="color:#e6db74">)</span><span style="color:#e6db74"> is </span><span style="color:#e6db74">\(</span>word.count<span style="color:#e6db74">)</span><span style="color:#e6db74">"</span>)
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 打印输出“the number of characters in cafe is 4”</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">var</span> emptyString = <span style="color:#e6db74">""</span> <span style="color:#75715e">// 空字符串字面量</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">var</span> anotherEmptyString = String() <span style="color:#75715e">// 初始化方法</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 两个字符串均为空并等价。</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">let</span> catCharacters: [Character] = [<span style="color:#e6db74">"C"</span>, <span style="color:#e6db74">"a"</span>, <span style="color:#e6db74">"t"</span>, <span style="color:#e6db74">"!"</span>]
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">let</span> catString = String(catCharacters)
</span></span><span style="display:flex;"><span>print(catString)
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 打印输出:“Cat!”</span>
</span></span></code></pre></div><h4 id="集合类型">集合类型</h4>
<p>Swift 语言提供数组(Array)、集合(Set)和字典(Dictionary)三种基本的集合类型用来存储集合数据。数组是有序数据的集。集合是无序无重复数据的集。字典是无序的键值对的集。
<strong>集合的可变性,数组(Arrays),集合(Sets),集合操作,字典</strong></p>
<p>数组使用有序列表存储同一类型的多个值。相同的值可以多次出现在一个数组的不同位置中。
集合用来存储相同类型并且没有确定顺序的值。当集合元素顺序不重要时或者希望确保每个元素只出现一次时可以使用集合而不是数组。
集合操作,可以高效地完成集合的一些基本操作,比如把两个集合组合到一起,判断两个集合共有元素,或者判断两个集合是否全包含,部分包含或者不相交。
字典是一种无序的集合,它存储的是键值对之间的关系,其所有键的值需要是相同的类型,所有值的类型也需要相同。每个值(value)都关联唯一的键(key),键作为字典中这个值数据的标识符。
示例:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span><span style="color:#75715e">// 集合</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">var</span> someInts = [Int]()
</span></span><span style="display:flex;"><span>print(<span style="color:#e6db74">"someInts is of type [Int] with </span><span style="color:#e6db74">\(</span>someInts.count<span style="color:#e6db74">)</span><span style="color:#e6db74"> items."</span>)
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 打印“someInts is of type [Int] with 0 items.”</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">var</span> threeDoubles = Array(repeating: <span style="color:#ae81ff">0.0</span>, count: <span style="color:#ae81ff">3</span>)
</span></span><span style="display:flex;"><span><span style="color:#75715e">// threeDoubles 是一种 [Double] 数组,等价于 [0.0, 0.0, 0.0]</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">var</span> anotherThreeDoubles = Array(repeating: <span style="color:#ae81ff">2.5</span>, count: <span style="color:#ae81ff">3</span>)
</span></span><span style="display:flex;"><span><span style="color:#75715e">// anotherThreeDoubles 被推断为 [Double],等价于 [2.5, 2.5, 2.5]</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">var</span> sixDoubles = threeDoubles <span style="color:#f92672">+</span> anotherThreeDoubles
</span></span><span style="display:flex;"><span><span style="color:#75715e">// sixDoubles 被推断为 [Double],等价于 [0.0, 0.0, 0.0, 2.5, 2.5, 2.5]</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// enumerated() 方法遍历数组</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">var</span> shoppingList: [String] = [<span style="color:#e6db74">"Eggs"</span>, <span style="color:#e6db74">"Milk"</span>]
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">for</span> (index, value) <span style="color:#66d9ef">in</span> shoppingList.enumerated() {
</span></span><span style="display:flex;"><span> print(<span style="color:#e6db74">"Item </span><span style="color:#e6db74">\(</span>String<span style="color:#e6db74">(</span>index <span style="color:#f92672">+</span> <span style="color:#ae81ff">1</span><span style="color:#e6db74">))</span><span style="color:#e6db74">: </span><span style="color:#e6db74">\(</span>value<span style="color:#e6db74">)</span><span style="color:#e6db74">"</span>)
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><h4 id="控制流">控制流</h4>
<p><strong>For-In 循环,While 循环(Repeat-While),条件语句,控制转移语句,提前退出(guard),检测 API 可用性</strong></p>
<p>像 if 语句一样,guard 的执行取决于一个表达式的布尔值。我们可以使用 guard 语句来要求条件必须为真时,以执行 guard 语句后的代码。不同于 if 语句,一个 guard 语句总是有一个 else 从句,如果条件不为真则执行 else 从句中的代码。
Swift 内置支持检查 API 可用性,编译器使用 SDK 中的可用信息来验证我们的代码中使用的所有 API 在项目指定的部署目标上是否可用。如果我们尝试使用一个不可用的 API,Swift 会在编译时报错。
示例:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span><span style="color:#66d9ef">let</span> names = [<span style="color:#e6db74">"Anna"</span>, <span style="color:#e6db74">"Alex"</span>, <span style="color:#e6db74">"Brian"</span>, <span style="color:#e6db74">"Jack"</span>]
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">for</span> name <span style="color:#66d9ef">in</span> names {
</span></span><span style="display:flex;"><span> print(<span style="color:#e6db74">"Hello, </span><span style="color:#e6db74">\(</span>name<span style="color:#e6db74">)</span><span style="color:#e6db74">!"</span>)
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">let</span> numberOfLegs = [<span style="color:#e6db74">"spider"</span>: <span style="color:#ae81ff">8</span>, <span style="color:#e6db74">"ant"</span>: <span style="color:#ae81ff">6</span>, <span style="color:#e6db74">"cat"</span>: <span style="color:#ae81ff">4</span>]
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">for</span> (animalName, legCount) <span style="color:#66d9ef">in</span> numberOfLegs {
</span></span><span style="display:flex;"><span> print(<span style="color:#e6db74">"</span><span style="color:#e6db74">\(</span>animalName<span style="color:#e6db74">)</span><span style="color:#e6db74">s have </span><span style="color:#e6db74">\(</span>legCount<span style="color:#e6db74">)</span><span style="color:#e6db74"> legs"</span>)
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// repeat-while 循环的一般格式</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">repeat</span> {
</span></span><span style="display:flex;"><span> statements
</span></span><span style="display:flex;"><span>} <span style="color:#66d9ef">while</span> condition
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 提前退出</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">greet</span>(person: [String: String]) {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">guard</span> <span style="color:#66d9ef">let</span> name = person[<span style="color:#e6db74">"name"</span>] <span style="color:#66d9ef">else</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span>
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> print(<span style="color:#e6db74">"Hello </span><span style="color:#e6db74">\(</span>name<span style="color:#e6db74">)</span><span style="color:#e6db74">!"</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">guard</span> <span style="color:#66d9ef">let</span> location = person[<span style="color:#e6db74">"location"</span>] <span style="color:#66d9ef">else</span> {
</span></span><span style="display:flex;"><span> print(<span style="color:#e6db74">"I hope the weather is nice near you."</span>)
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span>
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> print(<span style="color:#e6db74">"I hope the weather is nice in </span><span style="color:#e6db74">\(</span>location<span style="color:#e6db74">)</span><span style="color:#e6db74">."</span>)
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>greet(person: [<span style="color:#e6db74">"name"</span>: <span style="color:#e6db74">"John"</span>])
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 输出“Hello John!”</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 输出“I hope the weather is nice near you.”</span>
</span></span><span style="display:flex;"><span>greet(person: [<span style="color:#e6db74">"name"</span>: <span style="color:#e6db74">"Jane"</span>, <span style="color:#e6db74">"location"</span>: <span style="color:#e6db74">"Cupertino"</span>])
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 输出“Hello Jane!”</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 输出“I hope the weather is nice in Cupertino.”</span>
</span></span></code></pre></div><h4 id="函数">函数</h4>
<p><strong>函数的定义与调用,函数参数与返回值,函数参数标签和参数名称,函数类型,嵌套函数</strong></p>
<p>可选元组返回类型。
定义一个输入输出参数时,在参数定义前加 inout 关键字。
示例:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span><span style="color:#75715e">// 函数</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">greet</span>(person: String) -> String {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">let</span> greeting = <span style="color:#e6db74">"Hello, "</span> <span style="color:#f92672">+</span> person <span style="color:#f92672">+</span> <span style="color:#e6db74">"!"</span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> greeting
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">greet</span>(person: String, from hometown: String) -> String {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> <span style="color:#e6db74">"Hello </span><span style="color:#e6db74">\(</span>person<span style="color:#e6db74">)</span><span style="color:#e6db74">! Glad you could visit from </span><span style="color:#e6db74">\(</span>hometown<span style="color:#e6db74">)</span><span style="color:#e6db74">."</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>print(greet(person: <span style="color:#e6db74">"Bill"</span>, from: <span style="color:#e6db74">"Cupertino"</span>))
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 打印“Hello Bill! Glad you could visit from Cupertino.”</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 可选元组返回类型</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">minMax</span>(array: [Int]) -> (min: Int, max: Int)? {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> array.isEmpty { <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">nil</span> }
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> currentMin = array[<span style="color:#ae81ff">0</span>]
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> currentMax = array[<span style="color:#ae81ff">0</span>]
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">for</span> value <span style="color:#66d9ef">in</span> array[<span style="color:#ae81ff">1.</span>.<array.count] {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> value <span style="color:#f92672"><</span> currentMin {
</span></span><span style="display:flex;"><span> currentMin = value
</span></span><span style="display:flex;"><span> } <span style="color:#66d9ef">else</span> <span style="color:#66d9ef">if</span> value <span style="color:#f92672">></span> currentMax {
</span></span><span style="display:flex;"><span> currentMax = value
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> (currentMin, currentMax)
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 隐式返回的函数</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">greeting</span>(<span style="color:#66d9ef">for</span> person: String) -> String {
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"Hello, "</span> <span style="color:#f92672">+</span> person <span style="color:#f92672">+</span> <span style="color:#e6db74">"!"</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>print(greeting(<span style="color:#66d9ef">for</span>: <span style="color:#e6db74">"Dave"</span>))
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 打印 "Hello, Dave!</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 参数标签</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">greet</span>(person: String, from hometown: String) -> String {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> <span style="color:#e6db74">"Hello </span><span style="color:#e6db74">\(</span>person<span style="color:#e6db74">)</span><span style="color:#e6db74">! Glad you could visit from </span><span style="color:#e6db74">\(</span>hometown<span style="color:#e6db74">)</span><span style="color:#e6db74">."</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>print(greet(person: <span style="color:#e6db74">"Bill"</span>, from: <span style="color:#e6db74">"Cupertino"</span>))
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 打印“Hello Bill! Glad you could visit from Cupertino.”</span>
</span></span></code></pre></div><h4 id="闭包">闭包</h4>
<p>闭包是自包含的函数代码块,可以在代码中被传递和使用。与一些编程语言中的匿名函数(Lambdas)比较相似。
<strong>闭包表达式,尾随闭包,值捕获,闭包是引用类型,逃逸闭包(@escaping),自动闭包</strong></p>
<p>如果你需要将一个很长的闭包表达式作为最后一个参数传递给函数,将这个闭包替换成为尾随闭包的形式很有用。
闭包可以在其被定义的上下文中捕获常量或变量。即使定义这些常量和变量的原作用域已经不存在,闭包仍然可以在闭包函数体内引用和修改这些值。
示例:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span><span style="color:#75715e">// 闭包表达式语法</span>
</span></span><span style="display:flex;"><span>{ (parameters) -> <span style="color:#66d9ef">return</span> type <span style="color:#66d9ef">in</span>
</span></span><span style="display:flex;"><span> statements
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 尾随闭包</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">let</span> digitNames = [
</span></span><span style="display:flex;"><span> <span style="color:#ae81ff">0</span>: <span style="color:#e6db74">"Zero"</span>, <span style="color:#ae81ff">1</span>: <span style="color:#e6db74">"One"</span>, <span style="color:#ae81ff">2</span>: <span style="color:#e6db74">"Two"</span>, <span style="color:#ae81ff">3</span>: <span style="color:#e6db74">"Three"</span>, <span style="color:#ae81ff">4</span>: <span style="color:#e6db74">"Four"</span>,
</span></span><span style="display:flex;"><span> <span style="color:#ae81ff">5</span>: <span style="color:#e6db74">"Five"</span>, <span style="color:#ae81ff">6</span>: <span style="color:#e6db74">"Six"</span>, <span style="color:#ae81ff">7</span>: <span style="color:#e6db74">"Seven"</span>, <span style="color:#ae81ff">8</span>: <span style="color:#e6db74">"Eight"</span>, <span style="color:#ae81ff">9</span>: <span style="color:#e6db74">"Nine"</span>
</span></span><span style="display:flex;"><span>]
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">let</span> numbers = [<span style="color:#ae81ff">16</span>, <span style="color:#ae81ff">58</span>, <span style="color:#ae81ff">510</span>]
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">let</span> strings = numbers.map {
</span></span><span style="display:flex;"><span> (number) -> String <span style="color:#66d9ef">in</span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> number = number
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> output = <span style="color:#e6db74">""</span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">repeat</span> {
</span></span><span style="display:flex;"><span> output = digitNames[number <span style="color:#f92672">%</span> <span style="color:#ae81ff">10</span>]<span style="color:#f92672">!</span> <span style="color:#f92672">+</span> output
</span></span><span style="display:flex;"><span> number <span style="color:#f92672">/=</span> <span style="color:#ae81ff">10</span>
</span></span><span style="display:flex;"><span> } <span style="color:#66d9ef">while</span> number <span style="color:#f92672">></span> <span style="color:#ae81ff">0</span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> output
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#75715e">// strings 常量被推断为字符串类型数组,即 [String]</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 其值为 ["OneSix", "FiveEight", "FiveOneZero"]</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 值捕获</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">makeIncrementer</span>(forIncrement amount: Int) -> () -> Int {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> runningTotal = <span style="color:#ae81ff">0</span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">func</span> <span style="color:#a6e22e">incrementer</span>() -> Int {
</span></span><span style="display:flex;"><span> runningTotal <span style="color:#f92672">+=</span> amount
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> runningTotal
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> incrementer
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 自动闭包,延迟求值</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">var</span> customersInLine = [<span style="color:#e6db74">"Chris"</span>, <span style="color:#e6db74">"Alex"</span>, <span style="color:#e6db74">"Ewa"</span>, <span style="color:#e6db74">"Barry"</span>, <span style="color:#e6db74">"Daniella"</span>]
</span></span><span style="display:flex;"><span>print(customersInLine.count)
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 打印出“5”</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">let</span> customerProvider = { customersInLine.remove(at: <span style="color:#ae81ff">0</span>) }
</span></span><span style="display:flex;"><span>print(customersInLine.count)
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 打印出“5”</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>print(<span style="color:#e6db74">"Now serving </span><span style="color:#e6db74">\(</span>customerProvider<span style="color:#e6db74">())</span><span style="color:#e6db74">!"</span>)
</span></span><span style="display:flex;"><span><span style="color:#75715e">// Prints "Now serving Chris!"</span>
</span></span><span style="display:flex;"><span>print(customersInLine.count)
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 打印出“4”</span>
</span></span></code></pre></div><h4 id="枚举">枚举</h4>
<p>使用 enum 关键词来创建枚举并且把它们的整个定义放在一对大括号内。
<strong>枚举语法,使用 Switch 语句匹配枚举值,枚举成员的遍历,关联值,原始值(默认值),递归枚举(indirect)</strong></p>
<p>可以定义 Swift 枚举来存储任意类型的关联值,每个枚举成员的关联值类型可以各不相同。
示例:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span><span style="color:#75715e">// 枚举语法</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">enum</span> <span style="color:#a6e22e">SomeEnumeration</span> {
</span></span><span style="display:flex;"><span> <span style="color:#75715e">// 枚举定义放在这里</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">enum</span> <span style="color:#a6e22e">CompassPoint</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">case</span> north
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">case</span> south
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">case</span> east
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">case</span> west
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">enum</span> <span style="color:#a6e22e">Planet</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">case</span> mercury, venus, earth, mars, jupiter, saturn, uranus, neptune
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">let</span> somePlanet = Planet.earth
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">switch</span> somePlanet {
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">case</span> .earth:
</span></span><span style="display:flex;"><span> print(<span style="color:#e6db74">"Mostly harmless"</span>)
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">default</span>:
</span></span><span style="display:flex;"><span> print(<span style="color:#e6db74">"Not a safe place for humans"</span>)
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 打印“Mostly harmless”</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 关联值</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">enum</span> <span style="color:#a6e22e">Barcode</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">case</span> upc(Int, Int, Int, Int)
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">case</span> qrCode(String)
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">var</span> productBarcode = Barcode.upc(<span style="color:#ae81ff">8</span>, <span style="color:#ae81ff">85909</span>, <span style="color:#ae81ff">51226</span>, <span style="color:#ae81ff">3</span>)
</span></span><span style="display:flex;"><span>productBarcode = .qrCode(<span style="color:#e6db74">"ABCDEFGHIJKLMNOP"</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">switch</span> productBarcode {
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">case</span> <span style="color:#66d9ef">let</span> .upc(numberSystem, manufacturer, product, check):
</span></span><span style="display:flex;"><span> print(<span style="color:#e6db74">"UPC: </span><span style="color:#e6db74">\(</span>numberSystem<span style="color:#e6db74">)</span><span style="color:#e6db74">, </span><span style="color:#e6db74">\(</span>manufacturer<span style="color:#e6db74">)</span><span style="color:#e6db74">, </span><span style="color:#e6db74">\(</span>product<span style="color:#e6db74">)</span><span style="color:#e6db74">, </span><span style="color:#e6db74">\(</span>check<span style="color:#e6db74">)</span><span style="color:#e6db74">."</span>)
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">case</span> <span style="color:#66d9ef">let</span> .qrCode(productCode):
</span></span><span style="display:flex;"><span> print(<span style="color:#e6db74">"QR code: </span><span style="color:#e6db74">\(</span>productCode<span style="color:#e6db74">)</span><span style="color:#e6db74">."</span>)
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 打印“QR code: ABCDEFGHIJKLMNOP.”</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 递归枚举</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">indirect</span> <span style="color:#66d9ef">enum</span> <span style="color:#a6e22e">ArithmeticExpression</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">case</span> number(Int)
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">case</span> addition(ArithmeticExpression, ArithmeticExpression)
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">case</span> multiplication(ArithmeticExpression, ArithmeticExpression)
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">let</span> five = ArithmeticExpression.number(<span style="color:#ae81ff">5</span>)
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">let</span> four = ArithmeticExpression.number(<span style="color:#ae81ff">4</span>)
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">let</span> sum = ArithmeticExpression.addition(five, four)
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">let</span> product = ArithmeticExpression.multiplication(sum, ArithmeticExpression.number(<span style="color:#ae81ff">2</span>))
</span></span><span style="display:flex;"><span><span style="color:#75715e">// (5 + 4) * 2</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">evaluate</span>(<span style="color:#66d9ef">_</span> expression: ArithmeticExpression) -> Int {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">switch</span> expression {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">case</span> <span style="color:#66d9ef">let</span> .number(value):
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> value
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">case</span> <span style="color:#66d9ef">let</span> .addition(<span style="color:#66d9ef">left</span>, <span style="color:#66d9ef">right</span>):
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> evaluate(<span style="color:#66d9ef">left</span>) <span style="color:#f92672">+</span> evaluate(<span style="color:#66d9ef">right</span>)
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">case</span> <span style="color:#66d9ef">let</span> .multiplication(<span style="color:#66d9ef">left</span>, <span style="color:#66d9ef">right</span>):
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> evaluate(<span style="color:#66d9ef">left</span>) <span style="color:#f92672">*</span> evaluate(<span style="color:#66d9ef">right</span>)
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>print(evaluate(product))
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 打印“18”</span>
</span></span></code></pre></div><h4 id="结构体和类">结构体和类</h4>
<p><strong>结构体和类对比,结构体和枚举是值类型,类是引用类型</strong></p>
<p>结构体和类作为一种通用而又灵活的结构,成为了人们构建代码的基础。你可以使用定义常量、变量和函数的语法,为你的结构体和类定义属性、添加方法。
示例:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span><span style="color:#75715e">// 类和结构体</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#a6e22e">SomeStructure</span> {
</span></span><span style="display:flex;"><span> <span style="color:#75715e">// 在这里定义结构体</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">SomeClass</span> {
</span></span><span style="display:flex;"><span> <span style="color:#75715e">// 在这里定义类</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#a6e22e">Resolution</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> width = <span style="color:#ae81ff">0</span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> height = <span style="color:#ae81ff">0</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">VideoMode</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> resolution = Resolution()
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> interlaced = <span style="color:#66d9ef">false</span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> frameRate = <span style="color:#ae81ff">0.0</span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> name: String?
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><h4 id="属性">属性</h4>
<p><strong>存储属性,计算属性,属性观察器,属性包装器,全局变量和局部变量,类型属性(static)</strong></p>
<p>属性将值与特定的类、结构体或枚举关联。存储属性会将常量和变量存储为实例的一部分,而计算属性则是直接计算(而不是存储)值。计算属性可以用于类、结构体和枚举,而存储属性只能用于类和结构体。
属性观察器监控和响应属性值的变化,每次属性被设置值的时候都会调用属性观察器,即使新值和当前值相同的时候也不例外。</p>
<ul>
<li>willSet 在新的值被设置之前调用</li>
<li>didSet 在新的值被设置之后调用</li>
</ul>
<p>属性包装器在管理属性如何存储和定义属性的代码之间添加了一个分隔层。
类型属性也是通过点运算符来访问。但是,类型属性是通过类型本身来访问,而不是通过实例。
示例:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span><span style="color:#75715e">// 属性</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#a6e22e">Point</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> x = <span style="color:#ae81ff">0.0</span>, y = <span style="color:#ae81ff">0.0</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#a6e22e">Size</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> width = <span style="color:#ae81ff">0.0</span>, height = <span style="color:#ae81ff">0.0</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#a6e22e">Rect</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> origin = Point()
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> size = Size() <span style="color:#75715e">//存储属性</span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> center: Point { <span style="color:#75715e">//计算型属性</span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">get</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">let</span> centerX = origin.x <span style="color:#f92672">+</span> (size.width <span style="color:#f92672">/</span> <span style="color:#ae81ff">2</span>)
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">let</span> centerY = origin.y <span style="color:#f92672">+</span> (size.height <span style="color:#f92672">/</span> <span style="color:#ae81ff">2</span>)
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> Point(x: centerX, y: centerY)
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">set</span>(newCenter) {
</span></span><span style="display:flex;"><span> origin.x = newCenter.x <span style="color:#f92672">-</span> (size.width <span style="color:#f92672">/</span> <span style="color:#ae81ff">2</span>)
</span></span><span style="display:flex;"><span> origin.y = newCenter.y <span style="color:#f92672">-</span> (size.height <span style="color:#f92672">/</span> <span style="color:#ae81ff">2</span>)
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">var</span> square = Rect(origin: Point(x: <span style="color:#ae81ff">0.0</span>, y: <span style="color:#ae81ff">0.0</span>),
</span></span><span style="display:flex;"><span> size: Size(width: <span style="color:#ae81ff">10.0</span>, height: <span style="color:#ae81ff">10.0</span>))
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">let</span> initialSquareCenter = square.center
</span></span><span style="display:flex;"><span>square.center = Point(x: <span style="color:#ae81ff">15.0</span>, y: <span style="color:#ae81ff">15.0</span>)
</span></span><span style="display:flex;"><span>print(<span style="color:#e6db74">"square.origin is now at (</span><span style="color:#e6db74">\(</span>square.origin.x<span style="color:#e6db74">)</span><span style="color:#e6db74">, </span><span style="color:#e6db74">\(</span>square.origin.y<span style="color:#e6db74">)</span><span style="color:#e6db74">)"</span>)
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 打印“square.origin is now at (10.0, 10.0)”</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 属性包装器</span>
</span></span><span style="display:flex;"><span>@propertyWrapper
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#a6e22e">TwelveOrLess</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">var</span> number = <span style="color:#ae81ff">0</span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> wrappedValue: Int {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">get</span> { <span style="color:#66d9ef">return</span> number }
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">set</span> { number = min(newValue, <span style="color:#ae81ff">12</span>) }
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><h4 id="方法">方法</h4>
<p><strong>实例方法(Instance Methods),类型方法(static)</strong></p>
<p>方法是与某些特定类型相关联的函数。
类、结构体、枚举都可以定义实例方法;实例方法为给定类型的实例封装了具体的任务与功能。
类、结构体、枚举也可以定义类型方法;类型方法与类型本身相关联。
示例:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span><span style="color:#75715e">// 方法</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Counter</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> count = <span style="color:#ae81ff">0</span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">func</span> <span style="color:#a6e22e">increment</span>() {
</span></span><span style="display:flex;"><span> count <span style="color:#f92672">+=</span> <span style="color:#ae81ff">1</span>
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">func</span> <span style="color:#a6e22e">increment</span>(by amount: Int) {
</span></span><span style="display:flex;"><span> count <span style="color:#f92672">+=</span> amount
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">func</span> <span style="color:#a6e22e">reset</span>() {
</span></span><span style="display:flex;"><span> count = <span style="color:#ae81ff">0</span>
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><h4 id="下标">下标</h4>
<p>下标可以定义在类、结构体和枚举中,是访问集合、列表或序列中元素的快捷方式
下标语法(subscript),下标用法,下标选项,类型下标(static)</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span><span style="color:#66d9ef">subscript</span>(index: Int) -> Int {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">get</span> {
</span></span><span style="display:flex;"><span> <span style="color:#75715e">// 返回一个适当的 Int 类型的值</span>
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">set</span>(newValue) {
</span></span><span style="display:flex;"><span> <span style="color:#75715e">// 执行适当的赋值操作</span>
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 示例</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#a6e22e">TimesTable</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">let</span> multiplier: Int
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">subscript</span>(index: Int) -> Int {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> multiplier <span style="color:#f92672">*</span> index
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">let</span> threeTimesTable = TimesTable(multiplier: <span style="color:#ae81ff">3</span>)
</span></span><span style="display:flex;"><span>print(<span style="color:#e6db74">"six times three is </span><span style="color:#e6db74">\(</span>threeTimesTable[<span style="color:#ae81ff">6</span>]<span style="color:#e6db74">)</span><span style="color:#e6db74">"</span>)
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 打印“six times three is 18”</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">var</span> numberOfLegs = [<span style="color:#e6db74">"spider"</span>: <span style="color:#ae81ff">8</span>, <span style="color:#e6db74">"ant"</span>: <span style="color:#ae81ff">6</span>, <span style="color:#e6db74">"cat"</span>: <span style="color:#ae81ff">4</span>]
</span></span><span style="display:flex;"><span>numberOfLegs[<span style="color:#e6db74">"bird"</span>] = <span style="color:#ae81ff">2</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 类型下标</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">enum</span> <span style="color:#a6e22e">Planet</span>: Int {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">case</span> mercury = <span style="color:#ae81ff">1</span>, venus, earth, mars, jupiter, saturn, uranus, neptune
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">subscript</span>(n: Int) -> Planet {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> Planet(rawValue: n)<span style="color:#f92672">!</span>
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">let</span> mars = Planet[<span style="color:#ae81ff">4</span>]
</span></span><span style="display:flex;"><span>print(mars)
</span></span></code></pre></div><h4 id="继承">继承</h4>
<p><strong>定义一个基类,子类生成,重写(override),防止重写(final)</strong></p>
<p>不继承于其它类的类,称之为基类。
示例:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span><span style="color:#75715e">// 继承</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">SomeClass</span>: SomeSuperclass {
</span></span><span style="display:flex;"><span> <span style="color:#75715e">// 这里是子类的定义</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Vehicle</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> currentSpeed = <span style="color:#ae81ff">0.0</span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> description: String {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> <span style="color:#e6db74">"traveling at </span><span style="color:#e6db74">\(</span>currentSpeed<span style="color:#e6db74">)</span><span style="color:#e6db74"> miles per hour"</span>
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">func</span> <span style="color:#a6e22e">makeNoise</span>() {
</span></span><span style="display:flex;"><span> <span style="color:#75715e">// 什么也不做——因为车辆不一定会有噪音</span>
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Car</span>: Vehicle {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> gear = <span style="color:#ae81ff">1</span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">override</span> <span style="color:#66d9ef">var</span> description: String {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">super</span>.description <span style="color:#f92672">+</span> <span style="color:#e6db74">" in gear </span><span style="color:#e6db74">\(</span>gear<span style="color:#e6db74">)</span><span style="color:#e6db74">"</span>
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">AutomaticCar</span>: Car {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">override</span> <span style="color:#66d9ef">var</span> currentSpeed: Double {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">didSet</span> {
</span></span><span style="display:flex;"><span> gear = Int(currentSpeed <span style="color:#f92672">/</span> <span style="color:#ae81ff">10.0</span>) <span style="color:#f92672">+</span> <span style="color:#ae81ff">1</span>
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><h4 id="构造过程">构造过程</h4>
<p>构造过程是使用类、结构体或枚举类型的实例之前的准备过程。
<strong>存储属性的初始赋值,自定义构造过程,默认构造器,值类型的构造器代理,类的继承和构造过程,可失败构造器,必要构造器(required)</strong></p>
<p>构造器可以通过调用其它构造器来完成实例的部分构造过程。这一过程称为构造器代理,它能避免多个构造器间的代码重复。
Swift 为类类型提供了两种构造器来确保实例中所有存储型属性都能获得初始值,它们被称为指定构造器和便利构造器。
可以在一个类,结构体或是枚举类型的定义中,添加一个或多个可失败构造器。其语法为在 init 关键字后面添加问号(init?)。
必要构造器,在类的构造器前添加 required 修饰符表明所有该类的子类都必须实现该构造器。
示例:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span><span style="color:#75715e">// 构造过程</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">init</span>() {
</span></span><span style="display:flex;"><span> <span style="color:#75715e">// 在此处执行构造过程</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#a6e22e">Fahrenheit</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> temperature: Double
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">init</span>() {
</span></span><span style="display:flex;"><span> temperature = <span style="color:#ae81ff">32.0</span>
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">var</span> f = Fahrenheit()
</span></span><span style="display:flex;"><span>print(<span style="color:#e6db74">"The default temperature is </span><span style="color:#e6db74">\(</span>f.temperature<span style="color:#e6db74">)</span><span style="color:#e6db74">° Fahrenheit"</span>)
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 打印“The default temperature is 32.0° Fahrenheit”</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#a6e22e">Color</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">let</span> red, green, blue: Double
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">init</span>(red: Double, green: Double, blue: Double) {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">self</span>.red = red
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">self</span>.green = green
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">self</span>.blue = blue
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">init</span>(white: Double) {
</span></span><span style="display:flex;"><span> red = white
</span></span><span style="display:flex;"><span> green = white
</span></span><span style="display:flex;"><span> blue = white
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><h4 id="析构过程">析构过程</h4>
<p>析构器只适用于类类型,当一个类的实例被释放之前,析构器会被立即调用。析构器用关键字 deinit 来标示,类似于构造器要用 init 来标示。
Swift 会自动释放不再需要的实例以释放资源。
示例:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span><span style="color:#75715e">// 析构过程</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">deinit</span> {
</span></span><span style="display:flex;"><span> <span style="color:#75715e">// 执行析构过程</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Bank</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">var</span> coinsInBank = <span style="color:#ae81ff">10_000</span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">func</span> <span style="color:#a6e22e">distribute</span>(coins numberOfCoinsRequested: Int) -> Int {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">let</span> numberOfCoinsToVend = min(numberOfCoinsRequested, coinsInBank)
</span></span><span style="display:flex;"><span> coinsInBank <span style="color:#f92672">-=</span> numberOfCoinsToVend
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> numberOfCoinsToVend
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">func</span> <span style="color:#a6e22e">receive</span>(coins: Int) {
</span></span><span style="display:flex;"><span> coinsInBank <span style="color:#f92672">+=</span> coins
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Player</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> coinsInPurse: Int
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">init</span>(coins: Int) {
</span></span><span style="display:flex;"><span> coinsInPurse = Bank.distribute(coins: coins)
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">func</span> <span style="color:#a6e22e">win</span>(coins: Int) {
</span></span><span style="display:flex;"><span> coinsInPurse <span style="color:#f92672">+=</span> Bank.distribute(coins: coins)
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">deinit</span> {
</span></span><span style="display:flex;"><span> Bank.receive(coins: coinsInPurse)
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><h4 id="可选链式调用">可选链式调用</h4>
<p>可选链式调用是一种可以在当前值可能为 nil 的可选值上请求和调用属性、方法及下标的方法。
通过在想调用的属性、方法,或下标的可选值后面放一个问号(?),可以定义一个可选链。类似在可选值后面放一个叹号(!)来强制展开它的值。它们的主要区别在于当可选值为空时可选链式调用只会调用失败,然而强制展开将会触发运行时错误。
示例:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Person</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> residence: Residence?
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Residence</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> numberOfRooms = <span style="color:#ae81ff">1</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">let</span> john = Person()
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">let</span> roomCount = john.residence!.numberOfRooms
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 这会引发运行时错误</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#66d9ef">let</span> roomCount = john.residence?.numberOfRooms {
</span></span><span style="display:flex;"><span> print(<span style="color:#e6db74">"John's residence has </span><span style="color:#e6db74">\(</span>roomCount<span style="color:#e6db74">)</span><span style="color:#e6db74"> room(s)."</span>)
</span></span><span style="display:flex;"><span>} <span style="color:#66d9ef">else</span> {
</span></span><span style="display:flex;"><span> print(<span style="color:#e6db74">"Unable to retrieve the number of rooms."</span>)
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 打印“Unable to retrieve the number of rooms.”</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>john.residence = Residence()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#66d9ef">let</span> roomCount = john.residence?.numberOfRooms {
</span></span><span style="display:flex;"><span> print(<span style="color:#e6db74">"John's residence has </span><span style="color:#e6db74">\(</span>roomCount<span style="color:#e6db74">)</span><span style="color:#e6db74"> room(s)."</span>)
</span></span><span style="display:flex;"><span>} <span style="color:#66d9ef">else</span> {
</span></span><span style="display:flex;"><span> print(<span style="color:#e6db74">"Unable to retrieve the number of rooms."</span>)
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 打印“John's residence has 1 room(s).”</span>
</span></span></code></pre></div><h4 id="错误处理-1">错误处理</h4>
<p>错误处理(Error handling) 是响应错误以及从错误中恢复的过程。Swift 在运行时提供了抛出、捕获、传递和操作可恢复错误(recoverable errors)的一等支持。
<strong>表示与抛出错误,处理错误,指定清理操作</strong></p>
<p>在 Swift 中,错误用遵循 Error 协议的类型的值来表示。
Swift 中有 4 种处理错误的方式。可以把函数抛出的错误传递给调用此函数的代码(throws)、用 do-catch 语句处理错误、将错误作为可选类型处理(try?)、或者断言此错误根本不会发生(try!)。
defer 语句将代码的执行延迟到当前的作用域退出之前。
示例:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span><span style="color:#75715e">// 错误处理</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">enum</span> <span style="color:#a6e22e">VendingMachineError</span>: Error {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">case</span> invalidSelection <span style="color:#75715e">//选择无效</span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">case</span> insufficientFunds(coinsNeeded: Int) <span style="color:#75715e">//金额不足</span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">case</span> outOfStock <span style="color:#75715e">//缺货</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">throw</span> VendingMachineError.insufficientFunds(coinsNeeded: <span style="color:#ae81ff">5</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">var</span> vendingMachine = VendingMachine()
</span></span><span style="display:flex;"><span>vendingMachine.coinsDeposited = <span style="color:#ae81ff">8</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">do</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">try</span> buyFavoriteSnack(person: <span style="color:#e6db74">"Alice"</span>, vendingMachine: vendingMachine)
</span></span><span style="display:flex;"><span> print(<span style="color:#e6db74">"Success! Yum."</span>)
</span></span><span style="display:flex;"><span>} <span style="color:#66d9ef">catch</span> VendingMachineError.invalidSelection {
</span></span><span style="display:flex;"><span> print(<span style="color:#e6db74">"Invalid Selection."</span>)
</span></span><span style="display:flex;"><span>} <span style="color:#66d9ef">catch</span> VendingMachineError.outOfStock {
</span></span><span style="display:flex;"><span> print(<span style="color:#e6db74">"Out of Stock."</span>)
</span></span><span style="display:flex;"><span>} <span style="color:#66d9ef">catch</span> VendingMachineError.insufficientFunds(<span style="color:#66d9ef">let</span> coinsNeeded) {
</span></span><span style="display:flex;"><span> print(<span style="color:#e6db74">"Insufficient funds. Please insert an additional </span><span style="color:#e6db74">\(</span>coinsNeeded<span style="color:#e6db74">)</span><span style="color:#e6db74"> coins."</span>)
</span></span><span style="display:flex;"><span>} <span style="color:#66d9ef">catch</span> {
</span></span><span style="display:flex;"><span> print(<span style="color:#e6db74">"Unexpected error: </span><span style="color:#e6db74">\(</span>error<span style="color:#e6db74">)</span><span style="color:#e6db74">."</span>)
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 打印“Insufficient funds. Please insert an additional 2 coins.”</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 指定清理操作</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">processFile</span>(filename: String) <span style="color:#66d9ef">throws</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> exists(filename) {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">let</span> file = open(filename)
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">defer</span> {
</span></span><span style="display:flex;"><span> close(file)
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">while</span> <span style="color:#66d9ef">let</span> line = <span style="color:#66d9ef">try</span> file.readline() {
</span></span><span style="display:flex;"><span> <span style="color:#75715e">// 处理文件。</span>
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span> <span style="color:#75715e">// close(file) 会在这里被调用,即作用域的最后。</span>
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><h4 id="类型转换">类型转换</h4>
<p>类型转换在 Swift 中使用 is 和 as 操作符实现。这两个操作符分别提供了一种简单达意的方式去检查值的类型或者转换它的类型。
<strong>为类型转换定义类层次,检查类型(is),向下转型(as? 或 as!),Any 和 AnyObject 的类型转换</strong></p>
<p>可以将类型转换用在类和子类的层次结构上,检查特定类实例的类型并且转换这个类实例的类型成为这个层次结构中的其他类型。
Swift 为不确定类型提供了两种特殊的类型别名:</p>
<ul>
<li>
<p>Any 可以表示任何类型,包括函数类型。</p>
</li>
<li>
<p>AnyObject 可以表示任何类类型的实例。</p>
</li>
</ul>
<p>示例:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span><span style="color:#75715e">// 类型转换</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 一个基类 MediaItem</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">MediaItem</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> name: String
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">init</span>(name: String) {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">self</span>.name = name
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Movie</span>: MediaItem {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> director: String
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">init</span>(name: String, director: String) {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">self</span>.director = director
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">super</span>.<span style="color:#66d9ef">init</span>(name: name)
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Song</span>: MediaItem {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> artist: String
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">init</span>(name: String, artist: String) {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">self</span>.srtist = artist
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">super</span>.<span style="color:#66d9ef">init</span>(name: name)
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">let</span> library = [
</span></span><span style="display:flex;"><span> Movie(name: <span style="color:#e6db74">"Casablanca"</span>, director: <span style="color:#e6db74">"Micheal Curtiz"</span>),
</span></span><span style="display:flex;"><span> Song(name: <span style="color:#e6db74">"Blue Suede Shose"</span>, artist: <span style="color:#e6db74">"Elvis Presley"</span>),
</span></span><span style="display:flex;"><span> Movie(name: <span style="color:#e6db74">"Citizen Kane"</span>, director: <span style="color:#e6db74">"Orson Wells"</span>),
</span></span><span style="display:flex;"><span> Song(name: <span style="color:#e6db74">"The One And Only"</span>, artist: <span style="color:#e6db74">"Chesney Hawkes"</span>),
</span></span><span style="display:flex;"><span> Song(name: <span style="color:#e6db74">"Never Gonna Give You Up"</span>, artist: <span style="color:#e6db74">"Rick Astley"</span>)
</span></span><span style="display:flex;"><span>]
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">var</span> movieCount = <span style="color:#ae81ff">0</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">var</span> songCount = <span style="color:#ae81ff">0</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">for</span> item <span style="color:#66d9ef">in</span> library {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> item <span style="color:#66d9ef">is</span> Movie {
</span></span><span style="display:flex;"><span> movieCount <span style="color:#f92672">+=</span> <span style="color:#ae81ff">1</span>
</span></span><span style="display:flex;"><span> } <span style="color:#66d9ef">else</span> <span style="color:#66d9ef">if</span> item <span style="color:#66d9ef">is</span> Song {
</span></span><span style="display:flex;"><span> songCount <span style="color:#f92672">+=</span> <span style="color:#ae81ff">1</span>
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>print(<span style="color:#e6db74">"Media library contains </span><span style="color:#e6db74">\(</span>movieCount<span style="color:#e6db74">)</span><span style="color:#e6db74"> movies and </span><span style="color:#e6db74">\(</span>songCount<span style="color:#e6db74">)</span><span style="color:#e6db74">"</span>)
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 打印“Media library contains 2 movies and 3 songs”</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">for</span> item <span style="color:#66d9ef">in</span> library {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#66d9ef">let</span> movie = item <span style="color:#66d9ef">as</span>? Movie {
</span></span><span style="display:flex;"><span> print(<span style="color:#e6db74">"Movie: </span><span style="color:#e6db74">\(</span>movie.name<span style="color:#e6db74">)</span><span style="color:#e6db74">, dir. </span><span style="color:#e6db74">\(</span>movie.director<span style="color:#e6db74">)</span><span style="color:#e6db74">"</span>)
</span></span><span style="display:flex;"><span> } <span style="color:#66d9ef">else</span> <span style="color:#66d9ef">if</span> <span style="color:#66d9ef">let</span> song = item <span style="color:#66d9ef">as</span>? Song {
</span></span><span style="display:flex;"><span> print(<span style="color:#e6db74">"Song: </span><span style="color:#e6db74">\(</span>song.name<span style="color:#e6db74">)</span><span style="color:#e6db74">, by </span><span style="color:#e6db74">\(</span>song.artist<span style="color:#e6db74">)</span><span style="color:#e6db74">"</span>)
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#75715e">// Movie: Casablanca, dir. Michael Curtiz</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// Song: Blue Suede Shoes, by Elvis Presley</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// Movie: Citizen Kane, dir. Orson Welles</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// Song: The One And Only, by Chesney Hawkes</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// Song: Never Gonna Give You Up, by Rick Astley</span>
</span></span></code></pre></div><h4 id="嵌套类型">嵌套类型</h4>
<p>Swift 允许定义嵌套类型,可以在支持的类型中定义嵌套的枚举、类和结构体。
<strong>嵌套类型实践,引用嵌套类型</strong></p>
<p>要在一个类型中嵌套另一个类型,将嵌套类型的定义写在其外部类型的 {} 内,而且可以根据需要定义多级嵌套。
示例:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span><span style="color:#75715e">// 嵌套类型</span>
</span></span><span style="display:flex;"><span>stuct BlackjackCard {
</span></span><span style="display:flex;"><span> <span style="color:#75715e">// 嵌套的 Suit 枚举</span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">enum</span> <span style="color:#a6e22e">Suit</span>: Character {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">case</span> spades = <span style="color:#e6db74">"1"</span>, hearts = <span style="color:#e6db74">"2"</span>, diamonds = <span style="color:#e6db74">"3"</span>, clubs = <span style="color:#e6db74">"4"</span>
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#75715e">// 嵌套的 Rank 枚举</span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">enum</span> <span style="color:#a6e22e">Rank</span>: Int {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">case</span> two = <span style="color:#ae81ff">2</span>, three, four, five, six, seven, eight, nine, ten
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">case</span> jack, queen, king, ace
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">struct</span> <span style="color:#a6e22e">Values</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">let</span> first: Int, second: Int?
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> values: Values {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">switch</span> <span style="color:#66d9ef">self</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">case</span> .ace:
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> Values(first: <span style="color:#ae81ff">1</span>, second: <span style="color:#ae81ff">11</span>)
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">case</span> .jack, .queen, .king:
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> Values(first: <span style="color:#ae81ff">10</span>, second: <span style="color:#66d9ef">nil</span>)
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">default</span>:
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> Values(first: <span style="color:#66d9ef">self</span>.rawValue, second: <span style="color:#66d9ef">nil</span>)
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#75715e">// BlackjackCard 的属性和方法</span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">let</span> rank: Rank, suit: Suit
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> description: String {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> output = <span style="color:#e6db74">"suit is </span><span style="color:#e6db74">\(</span>suit.rawValue<span style="color:#e6db74">)</span><span style="color:#e6db74">,"</span>
</span></span><span style="display:flex;"><span> output <span style="color:#f92672">+=</span> <span style="color:#e6db74">" value is </span><span style="color:#e6db74">\(</span>rank.values.first<span style="color:#e6db74">)</span><span style="color:#e6db74">"</span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#66d9ef">let</span> second = rank.values.second {
</span></span><span style="display:flex;"><span> output <span style="color:#f92672">+=</span> <span style="color:#e6db74">" or </span><span style="color:#e6db74">\(</span>second<span style="color:#e6db74">)</span><span style="color:#e6db74">"</span>
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> output
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">let</span> theAceOfSpades = BlackjackCard(rank: .ace, suit: .spades)
</span></span><span style="display:flex;"><span>print(<span style="color:#e6db74">"theAceOfSpades: </span><span style="color:#e6db74">\(</span>theAceOfSpades.description<span style="color:#e6db74">)</span><span style="color:#e6db74">"</span>)
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 打印“theAceOfSpades: suit is 1, value is 1 or 11”</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">let</span> heartsSymbol = BlackjackCard.Suit.hearts.rawValue
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 2</span>
</span></span></code></pre></div><h4 id="扩展">扩展</h4>
<p>扩展可以给一个现有的类,结构体,枚举,还有协议添加新的功能。
<strong>扩展的语法,计算型属性,构造器,方法,下标,嵌套类型</strong></p>
<p>Swift 中的扩展可以:</p>
<ul>
<li>
<p>添加计算型实例属性和计算型类属性</p>
</li>
<li>
<p>定义实例方法和类方法</p>
</li>
<li>
<p>提供新的构造器</p>
</li>
<li>
<p>定义下标</p>
</li>
<li>
<p>定义和使用新的嵌套类型</p>
</li>
<li>
<p>使已经存在的类型遵循(conform)一个协议</p>
</li>
</ul>
<p>扩展语法:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span><span style="color:#66d9ef">extension</span> <span style="color:#a6e22e">SomeType</span> {
</span></span><span style="display:flex;"><span> <span style="color:#75715e">// 在这里给 SomeType 添加新的功能</span>
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>扩展可以给现有类型添加计算型实例属性和计算型类属性。
扩展可以给现有的类型添加新的构造器。
扩展可以给现有类型添加新的实例方法和类方法。
扩展可以给现有的类型添加新的下标。
扩展可以给现有的类,结构体,还有枚举添加新的嵌套类型。
示例:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span><span style="color:#75715e">// 扩展的语法</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">extension</span> <span style="color:#a6e22e">SomeType</span> {
</span></span><span style="display:flex;"><span> <span style="color:#75715e">// 在这里给 SomeType 添加新的功能</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 添加一个或多个协议</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">extension</span> <span style="color:#a6e22e">SomeType</span>: SomeProtocol, AnotherProtocol {
</span></span><span style="display:flex;"><span> <span style="color:#75715e">// 协议所需要的实现写在这里</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#a6e22e">Size</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> width = <span style="color:#ae81ff">0.0</span>, height = <span style="color:#ae81ff">0.0</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#a6e22e">Point</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> x = <span style="color:#ae81ff">0.0</span>, y = <span style="color:#ae81ff">0.0</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#a6e22e">Rect</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> origin = Point()
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> size = Size()
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">extension</span> <span style="color:#a6e22e">Rect</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">init</span>(center: Point, size: Size) {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">let</span> originX = center.x <span style="color:#f92672">-</span> (size.width <span style="color:#f92672">/</span> <span style="color:#ae81ff">2</span>)
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">let</span> originY = center.y <span style="color:#f92672">-</span> (size.height <span style="color:#f92672">/</span> <span style="color:#ae81ff">3</span>)
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">self</span>.<span style="color:#66d9ef">init</span>(origin: Point(x: originX, y: originY), size: size)
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">let</span> centerRect = Rect(center: Point(x: <span style="color:#ae81ff">4.0</span>, y: <span style="color:#ae81ff">4.0</span>),
</span></span><span style="display:flex;"><span> size: Size(width: <span style="color:#ae81ff">3.0</span>, height: <span style="color:#ae81ff">3.0</span>))
</span></span><span style="display:flex;"><span><span style="color:#75715e">// centerRect 的 origin 是 (2.5, 2.5) 并且它的 size 是 (3.0, 3.0)</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">extension</span> <span style="color:#a6e22e">Int</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">func</span> <span style="color:#a6e22e">repetitions</span>(task: () -> Void) {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">for</span> <span style="color:#66d9ef">_</span> <span style="color:#66d9ef">in</span> <span style="color:#ae81ff">0.</span>.<<span style="color:#66d9ef">self</span> {
</span></span><span style="display:flex;"><span> task()
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#ae81ff">3.</span>repetitions {
</span></span><span style="display:flex;"><span> print(<span style="color:#e6db74">"Hello!"</span>)
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#75715e">// Hello!</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// Hello!</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// Hello!</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">extension</span> <span style="color:#a6e22e">Int</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">mutating</span> <span style="color:#66d9ef">func</span> <span style="color:#a6e22e">square</span>() {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">self</span> = <span style="color:#66d9ef">self</span> <span style="color:#f92672">*</span> <span style="color:#66d9ef">self</span>
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">var</span> somtInt = <span style="color:#ae81ff">3</span>
</span></span><span style="display:flex;"><span>someInt.square()
</span></span><span style="display:flex;"><span><span style="color:#75715e">// someInt 现在是9</span>
</span></span></code></pre></div><h4 id="协议">协议</h4>
<p>协议定义了一个蓝图,规定了用来实现某一特定任务或者功能的方法、属性,以及其他需要的东西。
类、结构体或枚举都可以遵循协议,并为协议定义的这些要求提供具体实现。
协议语法,属性要求,方法要求,异变方法要求,构造器要求,协议作为类型,委托,协议类型的集合,协议的继承,类专属的协议,协议合成,检查协议一致性,可选的协议要求,协议扩展,</p>
<p>协议语法</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span><span style="color:#66d9ef">protocol</span> <span style="color:#a6e22e">SomeProtocol</span> {
</span></span><span style="display:flex;"><span> <span style="color:#75715e">// 这里是协议的定义部分</span>
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>协议可以要求遵循协议的类型提供特定名称和类型的实例属性或类型属性。
协议可以要求遵循协议的类型实现某些指定的实例方法或类方法。
在值类型(即结构体和枚举)的实例方法中,将 mutating 关键字作为方法的前缀,写在 func 关键字之前,表示可以在该方法中修改它所属的实例以及实例的任意属性的值。
协议可以要求遵循协议的类型实现指定的构造器。
委托是一种设计模式,它允许类或结构体将一些需要它们负责的功能委托给其他类型的实例。
示例:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span><span style="color:#75715e">// 协议语法</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">protocol</span> <span style="color:#a6e22e">SomeProtocol</span> {
</span></span><span style="display:flex;"><span> <span style="color:#75715e">// 这里是协议的定义部分</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#a6e22e">SomeStructure</span>: FirstProtocol, AnotherProtocol {
</span></span><span style="display:flex;"><span> <span style="color:#75715e">// 这里是结构体的定义部分</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">SomeClass</span>: SomeSuperClass, FirstProtocol, AnotherProtocol {
</span></span><span style="display:flex;"><span> <span style="color:#75715e">// 这里是类的定义部分</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">protocol</span> <span style="color:#a6e22e">SomeProtocol</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> mustBeSettable: Int { <span style="color:#66d9ef">get</span> <span style="color:#66d9ef">set</span> }
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> doesNotNeedToBeSettable: Int { <span style="color:#66d9ef">get</span> }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">protocol</span> <span style="color:#a6e22e">AnotherProtocol</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">var</span> someTypeProperty: Int { <span style="color:#66d9ef">get</span> <span style="color:#66d9ef">set</span> }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">protocol</span> <span style="color:#a6e22e">FullyNamed</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> fullName: String { <span style="color:#66d9ef">get</span> }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#a6e22e">person</span>: FullyNamed {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> fullName: String
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">let</span> john = Person(fullName: <span style="color:#e6db74">"John Appleseed"</span>)
</span></span><span style="display:flex;"><span><span style="color:#75715e">// john.fullName 为 "John Appleseed"</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Starship</span>: FullyNamed {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> prefix: String?
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> name: String
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">init</span>(name: String, <span style="color:#66d9ef">prefix</span>: String? = <span style="color:#66d9ef">nil</span>) {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">self</span>.name = name
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">self</span>.<span style="color:#66d9ef">prefix</span> = <span style="color:#66d9ef">prefix</span>
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> fullName: String {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> (<span style="color:#66d9ef">prefix</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> ? <span style="color:#66d9ef">prefix</span>! <span style="color:#f92672">+</span> <span style="color:#e6db74">" "</span> : <span style="color:#e6db74">""</span>) <span style="color:#f92672">+</span> name
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">var</span> ncc1701 = Starship(name: <span style="color:#e6db74">"Enterprise"</span>, <span style="color:#66d9ef">prefix</span>: <span style="color:#e6db74">"USS"</span>)
</span></span><span style="display:flex;"><span><span style="color:#75715e">// ncc1701.fullName 为 "USS Enterprise"</span>
</span></span></code></pre></div><h4 id="泛型">泛型</h4>
<p>泛型代码让你能根据自定义的需求,编写出适用于任意类型的、灵活可复用的函数及类型。
你可避免编写重复的代码,而是用一种清晰抽象的方式来表达代码的意图。
<strong>泛型函数,类型参数,命名类型参数,泛型类型,泛型扩展,类型约束,关联类型</strong></p>
<p>示例:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">swapTwoInts</span>(<span style="color:#66d9ef">_</span> a: <span style="color:#66d9ef">inout</span> Int, <span style="color:#66d9ef">_</span> b: <span style="color:#66d9ef">inout</span> Int) {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">let</span> temporaryA = a
</span></span><span style="display:flex;"><span> a = b
</span></span><span style="display:flex;"><span> b = temporaryA
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">swapTwoValues</span><T>(<span style="color:#66d9ef">_</span> a: <span style="color:#66d9ef">inout</span> T, <span style="color:#66d9ef">_</span> b: <span style="color:#66d9ef">inout</span> T) {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">let</span> temporaryA = a
</span></span><span style="display:flex;"><span> a = b
</span></span><span style="display:flex;"><span> b = temporaryA
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">swapTwoInts</span>(<span style="color:#66d9ef">_</span> a: <span style="color:#66d9ef">inout</span> Int, <span style="color:#66d9ef">_</span> b: <span style="color:#66d9ef">inout</span> Int)
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">swapTwoValues</span><T>(<span style="color:#66d9ef">_</span> a: <span style="color:#66d9ef">inout</span> T, <span style="color:#66d9ef">_</span> b: <span style="color:#66d9ef">inout</span> T)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">var</span> someInt = <span style="color:#ae81ff">3</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">var</span> anotherInt = <span style="color:#ae81ff">107</span>
</span></span><span style="display:flex;"><span>swapTwoValues(&someInt, &anotherInt)
</span></span><span style="display:flex;"><span><span style="color:#75715e">// someInt 现在是 107,anotherInt 现在是 3</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">var</span> someString = <span style="color:#e6db74">"hello"</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">var</span> anotherString = <span style="color:#e6db74">"world"</span>
</span></span><span style="display:flex;"><span>swapTwoValues(&someString, &anotherString)
</span></span><span style="display:flex;"><span><span style="color:#75715e">// someString 现在是“world”,anotherString 现在是“hello”</span>
</span></span></code></pre></div><h4 id="不透明类型">不透明类型</h4>
<p>具有不透明返回类型的函数或方法会隐藏返回值的类型信息。
函数不再提供具体的类型作为返回类型,而是根据它支持的协议来描述返回值。
<strong>不透明类型解决的问题,返回不透明类型,不透明类型和协议类型的区别</strong></p>
<p>在处理模块和调用代码之间的关系时,隐藏类型信息非常有用,因为返回的底层数据类型仍然可以保持私有。
不透明类型和泛型相反。不透明类型允许函数实现时,选择一个与调用代码无关的返回类型。
如果函数中有多个地方返回了不透明类型,那么所有可能的返回值都必须是同一类型。返回不透明类型和返回协议类型主要区别,就在于是否需要保证类型一致性。
一个不透明类型只能对应一个具体的类型,即便函数调用者并不能知道是哪一种类型;协议类型可以同时对应多个类型,只要它们都遵循同一协议。
示例:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span><span style="color:#66d9ef">protocol</span> <span style="color:#a6e22e">Shape</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">func</span> <span style="color:#a6e22e">draw</span>() -> String
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#a6e22e">Triangle</span>: Shape {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> size: Int
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">func</span> <span style="color:#a6e22e">draw</span>() -> String {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> result = [String]()
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">for</span> length <span style="color:#66d9ef">in</span> <span style="color:#ae81ff">1.</span>..size {
</span></span><span style="display:flex;"><span> result.append(String(repeating: <span style="color:#e6db74">"*"</span>, count: length))
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> result.joined(separator: <span style="color:#e6db74">"</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span>)
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">let</span> smallTriangle = Triangle(size: <span style="color:#ae81ff">3</span>)
</span></span><span style="display:flex;"><span>print(smallTriangle.draw())
</span></span><span style="display:flex;"><span><span style="color:#75715e">// *</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// **</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// ***</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#a6e22e">FlippedShape</span><T: Shape>: Shape {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> shape: T
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">func</span> <span style="color:#a6e22e">draw</span>() -> String {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">let</span> lines = shape.draw().split(separator: <span style="color:#e6db74">"</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span>)
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> lines.reversed().joined(separator: <span style="color:#e6db74">"</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span>)
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">let</span> flippedTriangle = FlippedShape(shape: smallTriangle)
</span></span><span style="display:flex;"><span>print(flippedTriangle.draw())
</span></span><span style="display:flex;"><span><span style="color:#75715e">// ***</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// **</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// *</span>
</span></span></code></pre></div><h4 id="自动引用计数">自动引用计数</h4>
<p>Swift 使用自动引用计数(ARC)机制来跟踪和管理你的应用程序的内存。
如果两个类实例互相持有对方的强引用,因而每个实例都让对方一直存在,就是这种情况。这就是所谓的循环强引用。
Swift提供了两种办法用来解决你在使用类的属性时所遇到的循环强引用问题:弱引用(weak reference)和无主引用(unowned reference)。</p>
<ul>
<li>
<p>声明属性或者变量时,在前面加上 weak 关键字表明这是一个弱引用。</p>
</li>
<li>
<p>声明属性或者变量时,在前面加上关键字 unowned 表示这是一个无主引用。</p>
</li>
</ul>
<p>示例:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span><span style="color:#75715e">// 自动引用计数实践</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Person</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">let</span> name: String
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">init</span>(name: String) {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">self</span>.name = name
</span></span><span style="display:flex;"><span> print(<span style="color:#e6db74">"</span><span style="color:#e6db74">\(</span>name<span style="color:#e6db74">)</span><span style="color:#e6db74"> is being initialized"</span>)
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">deinit</span> {
</span></span><span style="display:flex;"><span> print(<span style="color:#e6db74">"</span><span style="color:#e6db74">\(</span>name<span style="color:#e6db74">)</span><span style="color:#e6db74"> is being deinitialized"</span>)
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">var</span> reference1: Person?
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">var</span> reference2: Person?
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">var</span> reference3: Person?
</span></span><span style="display:flex;"><span>reference1 = Person(name: <span style="color:#e6db74">"John Appleseed"</span>)
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 打印“John Appleseed is being initialized”</span>
</span></span><span style="display:flex;"><span>reference2 = reference1
</span></span><span style="display:flex;"><span>reference3 = reference1
</span></span><span style="display:flex;"><span>reference1 = <span style="color:#66d9ef">nil</span>
</span></span><span style="display:flex;"><span>reference2 = <span style="color:#66d9ef">nil</span>
</span></span><span style="display:flex;"><span>reference3 = <span style="color:#66d9ef">nil</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 打印“John Appleseed is being deinitialized”</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 循环强引用</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Person</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">let</span> name: String
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">init</span>(name: String) { <span style="color:#66d9ef">self</span>.name = name }
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> apartment: Apartment?
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">deinit</span> { print(<span style="color:#e6db74">"</span><span style="color:#e6db74">\(</span>name<span style="color:#e6db74">)</span><span style="color:#e6db74"> is being deinitialized"</span>) }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Apartment</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">let</span> unit: String
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">init</span>(unit: String) { <span style="color:#66d9ef">self</span>.unit = unit }
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> tenant: Person?
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">deinit</span> { print(<span style="color:#e6db74">"Apartment </span><span style="color:#e6db74">\(</span>unit<span style="color:#e6db74">)</span><span style="color:#e6db74"> is being deinitialized"</span>) }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">var</span> john: Person?
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">var</span> unit4A: Apartment?
</span></span><span style="display:flex;"><span>john = Person(name: <span style="color:#e6db74">"John Appleseed"</span>)
</span></span><span style="display:flex;"><span>unit4A = Apartment(unit: <span style="color:#e6db74">"4A"</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>john = <span style="color:#66d9ef">nil</span>
</span></span><span style="display:flex;"><span>unit4A = <span style="color:#66d9ef">nil</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 弱引用</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Person</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">let</span> name: String
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">init</span>(name: String) { <span style="color:#66d9ef">self</span>.name = name }
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> apartment: Apartment?
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">deinit</span> { print(<span style="color:#e6db74">"</span><span style="color:#e6db74">\(</span>name<span style="color:#e6db74">)</span><span style="color:#e6db74"> is being deinitialized"</span>) }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Apartment</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">let</span> unit: String
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">init</span>(unit: String) { <span style="color:#66d9ef">self</span>.unit = unit }
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">weak</span> <span style="color:#66d9ef">var</span> tenant: Person?
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">deinit</span> { print(<span style="color:#e6db74">"Apartment </span><span style="color:#e6db74">\(</span>unit<span style="color:#e6db74">)</span><span style="color:#e6db74"> is being deinitialized"</span>) }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">var</span> john: Person?
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">var</span> unit4A: Apartment?
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>john = Person(name: <span style="color:#e6db74">"John Appleseed"</span>)
</span></span><span style="display:flex;"><span>unit4A = Apartment(unit: <span style="color:#e6db74">"4A"</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>john!.apartment = unit4A
</span></span><span style="display:flex;"><span>unit4A!.tenant = john
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>john = <span style="color:#66d9ef">nil</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 打印“John Appleseed is being deinitialized”</span>
</span></span></code></pre></div><h4 id="内存安全">内存安全</h4>
<p>默认情况下,Swift 会阻止你代码里不安全的行为。
理解内存访问冲突,In-Out 参数的访问冲突,方法里 self 的访问冲突,属性的访问冲突</p>
<p>示例:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">balance</span>(<span style="color:#66d9ef">_</span> x: <span style="color:#66d9ef">inout</span> Int, <span style="color:#66d9ef">_</span> y: <span style="color:#66d9ef">inout</span> Int) {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">let</span> sum = x <span style="color:#f92672">+</span> y
</span></span><span style="display:flex;"><span> x = sum <span style="color:#f92672">/</span> <span style="color:#ae81ff">2</span>
</span></span><span style="display:flex;"><span> y = sum <span style="color:#f92672">-</span> x
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">var</span> playerOneScore = <span style="color:#ae81ff">42</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">var</span> playerTwoScore = <span style="color:#ae81ff">30</span>
</span></span><span style="display:flex;"><span>balance(&playerOneScore, &playerTwoScore) <span style="color:#75715e">// 正常</span>
</span></span><span style="display:flex;"><span>balance(&playerOneScore, &playerOneScore)
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 错误:playerOneScore 访问冲突</span>
</span></span></code></pre></div><h4 id="访问控制">访问控制</h4>
<p>访问控制可以限定其它源文件或模块对你的代码的访问。</p>
<ul>
<li>
<p>open 和 public 级别可以让实体被同一模块源文件中的所有实体访问,在模块外也可以通过导入该模块来访问源文件里的所有实体。通常情况下,你会使用 open 或 public 级别来指定框架的外部接口。</p>
</li>
<li>
<p>internal 级别让实体被同一模块源文件中的任何实体访问,但是不能被模块外的实体访问。通常情况下,如果某个接口只在应用程序或框架内部使用,就可以将其设置为 internal 级别。</p>
</li>
<li>
<p>fileprivate 限制实体只能在其定义的文件内部访问。如果功能的部分实现细节只需要在文件内使用时,可以使用 fileprivate 来将其隐藏。</p>
</li>
<li>
<p>private 限制实体只能在其定义的作用域,以及同一文件内的 extension 访问。如果功能的部分细节只需要在当前作用域内使用时,可以使用 private 来将其隐藏。</p>
</li>
</ul>
<p>open 为最高访问级别(限制最少),private 为最低访问级别(限制最多)。
open 只能作用于类和类的成员,它和 public 的区别主要在于 open 限定的类和成员能够在模块外能被继承和重写。
示例:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">SomePublicClass</span> {}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">internal</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">SomeInternalClass</span> {}
</span></span><span style="display:flex;"><span>fileprivate <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">SomeFilePrivateClass</span> {}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">private</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">SomePrivateClass</span> {}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">SomeInternalClass</span> {} <span style="color:#75715e">// 隐式 internal</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">var</span> someInternalConstant = <span style="color:#ae81ff">0</span> <span style="color:#75715e">// 隐式 internal</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">SomePublicClass</span> { <span style="color:#75715e">// 显式 public 类</span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">var</span> somePublicProperty = <span style="color:#ae81ff">0</span> <span style="color:#75715e">// 显式 public 类成员</span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> someInternalProperty = <span style="color:#ae81ff">0</span> <span style="color:#75715e">// 隐式 internal 类成员</span>
</span></span><span style="display:flex;"><span> fileprivate <span style="color:#66d9ef">func</span> <span style="color:#a6e22e">someFilePrivateMethod</span>() {} <span style="color:#75715e">// 显式 fileprivate 类成员</span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">func</span> <span style="color:#a6e22e">somePrivateMethod</span>() {} <span style="color:#75715e">// 显式 private 类成员</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">SomeInternalClass</span> { <span style="color:#75715e">// 隐式 internal 类</span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> someInternalProperty = <span style="color:#ae81ff">0</span> <span style="color:#75715e">// 隐式 internal 类成员</span>
</span></span><span style="display:flex;"><span> fileprivate <span style="color:#66d9ef">func</span> <span style="color:#a6e22e">someFilePrivateMethod</span>() {} <span style="color:#75715e">// 显式 fileprivate 类成员</span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">func</span> <span style="color:#a6e22e">somePrivateMethod</span>() {} <span style="color:#75715e">// 显式 private 类成员</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>fileprivate <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">SomeFilePrivateClass</span> { <span style="color:#75715e">// 显式 fileprivate 类</span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">func</span> <span style="color:#a6e22e">someFilePrivateMethod</span>() {} <span style="color:#75715e">// 隐式 fileprivate 类成员</span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">func</span> <span style="color:#a6e22e">somePrivateMethod</span>() {} <span style="color:#75715e">// 显式 private 类成员</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">private</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">SomePrivateClass</span> { <span style="color:#75715e">// 显式 private 类</span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">func</span> <span style="color:#a6e22e">somePrivateMethod</span>() {} <span style="color:#75715e">// 隐式 private 类成员</span>
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><h4 id="高级运算符">高级运算符</h4>
<p>Swift还提供了数种可以对数值进行复杂运算的高级运算符。它们包含了位运算符和移位运算符。
<strong>位运算符、溢出运算符、优先级和结合性、运算符函数、自定义运算符</strong></p>
<p>示例:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span><span style="color:#66d9ef">let</span> initialBits: UInt8 = <span style="color:#ae81ff">0b00001111</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">let</span> invertedBits = <span style="color:#f92672">~</span>initialBits <span style="color:#75715e">// 等于 0b11110000</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">var</span> potentialOverflow = Int16.max
</span></span><span style="display:flex;"><span><span style="color:#75715e">// potentialOverflow 的值是 32767,这是 Int16 能容纳的最大整数</span>
</span></span><span style="display:flex;"><span>potentialOverflow <span style="color:#f92672">+=</span> <span style="color:#ae81ff">1</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 这里会报错</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#a6e22e">Vector2D</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> x = <span style="color:#ae81ff">0.0</span>, y = <span style="color:#ae81ff">0.0</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">extension</span> <span style="color:#a6e22e">Vector2D</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">func</span> <span style="color:#f92672">+</span> (<span style="color:#66d9ef">left</span>: Vector2D, <span style="color:#66d9ef">right</span>: Vector2D) -> Vector2D {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> Vector2D(x: <span style="color:#66d9ef">left</span>.x <span style="color:#f92672">+</span> <span style="color:#66d9ef">right</span>.x, y: <span style="color:#66d9ef">left</span>.y <span style="color:#f92672">+</span> <span style="color:#66d9ef">right</span>.y)
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">let</span> vector = Vector2D(x: <span style="color:#ae81ff">3.0</span>, y: <span style="color:#ae81ff">1.0</span>)
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">let</span> anotherVector = Vector2D(x: <span style="color:#ae81ff">2.0</span>, y: <span style="color:#ae81ff">4.0</span>)
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">let</span> combinedVector = vector <span style="color:#f92672">+</span> anotherVector
</span></span><span style="display:flex;"><span><span style="color:#75715e">// combinedVector 是一个新的 Vector2D 实例,值为 (5.0, 5.0)</span>
</span></span></code></pre></div>