Swift3.0 新的 GCD 和 Core Graphics
DispatchQueue
首先,dispatch 的全域性函式不再寫為下劃線風格的名稱了,它變成了一個更符合 Swift 風格的 DispatchQueue 的樣子。
main thread
同樣的,你不需要在去用 dispatch_get_main_queue ( ) 來獲取主執行緒,而是 DispatchQueue . main ,那麼要放到主執行緒的程式碼怎麼執行呢?只需要線上程後邊使用 . async { } 即可,也就是說,大概是這樣:
DispatchQueue.main.async { [weak self] in yourcoderunsin mainthread }
優先順序
說完了最基本的東西,我們再來說說其他改變了的東西,比如優先順序的名字。
我們知道,GCD 的預設佇列優先順序有四個:
- DISPATCH_QUEUE_PRIORITY_HIGH
- DISPATCH_QUEUE_PRIORITY_DEFAULT
- DISPATCH_QUEUE_PRIORITY_LOW
- DISPATCH_QUEUE_PRIORITY_BACKGROUND
現在,新的語法當中,改變了這四個不明不白的優先順序名稱為更有意義的名字:
- .userInitialted
- .default
- .utility
- .background
當然,它們的對應關係也就是與順序相同的:
DISPATCH_QUEUE_PRIORITY_HIGH: .userInitiated DISPATCH_QUEUE_PRIORITY_DEFAULT: .defaultDISPATCH_QUEUE_PRIORITY_LOW: .utility DISPATCH_QUEUE_PRIORITY_BACKGROUND: .background
獲取一個佇列
我們使用 DispatchQueue . global ( ) 獲取一個系統的佇列,這樣的話獲取的就是預設 . default 優先順序的隊列了,如果要獲取其他優先順序的佇列,就使用 DispatchQueue. global ( qos : . userInitiated ) ,最後,我們使用 . async { } 來執行程式碼:
DispatchQueue.global(qos: .userInitiated).async {
//your code here
}
建立一個佇列
直接用 DispatchQueue 的初始化器來建立一個佇列。最簡單直接的辦法是這樣:
let queue = DispatchQueue(label: "myBackgroundQueue")
複雜一點?你可以指定優先順序以及佇列類別:
let queue = DispatchQueue(label: "myBackgroundQueue", qos: .userInitiated, attributes: .concurrent)
然後把程式碼放進去即可:
- queue.async {
- <span class="keyword" style="font-weight:bold">print</span>(<span class="string" style="color:rgb(221,17,68)">"aaa"</span>)
- }
佇列打組
對於組,現在你可以使用這樣的語法直接建立一個組:
let group = DispatchGroup()
至於使用,則是這樣的:
let group = DispatchGroup() let queue = DispatchQueue(label: "myBackgroundQueue") queue.async(group:group) { print("background working") }
那麼,如果有多個併發佇列在同一個組裡,我們需要它們完成了再繼續呢?
group.wait()
指定時間後執行
很多時候你可能還需要讓一些程式碼在指定的時間後執行,比如動畫完成後。這個任務在swift 2.3 很麻煩,不過,在3.0就不一樣了:
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 3.0) {
print("after!")
}
只需要一句話即可。
其他變化:
升級到 Swift 3
在升級到 Swift 3 時,你會發現,基本上每個檔案都需要改動!之所以這樣,是因為所有的 Cocoa API 名稱都被改變了。簡而言之,API 仍然是原來的 API,但這個 API 在 Objective-C 中是一種叫法,而在 Swift 中又是另一種叫法了。Swift 3 語法書寫起來要更貼近於自然語言。
在 Xcode 8 中蘋果提供了 Migration Assistant,它可以完成大部分的遷移工作。但很顯然,仍然有一部分工作需要你手動完成。
你可以立即將程式碼升級到 2.3 或者 3.0。如果你需要將程式碼又轉回來,你可以用 Xcode 的 Edit > Convert > To Current Swift Syntax… 選單。編譯器會和 Migrateion Assistant 一樣智慧。如果你在呼叫方法時,偶然使用了老的 API,編譯器會顯示一個 Fixt-It 選項,讓你使用正確的新 API。幸好 Swift 3 在最終釋出時,才會停止改變原始碼。因此,你可以將你的 Swift 程式碼儲存為不同的版本。但是 Swift 核心團隊不能保證這一點以後不會改變,如果在某個時候不在保證原始碼上的相容,他們會提供一個較長的過渡期。這意味著原始碼是穩定的,這樣能鼓勵更多的保守的公司去使用它。
這也說明,二進位制穩定的目標還沒有達到。本文最後將討論這將導致的影響。
API 的改變
Swift 3 中最大的改變是標準庫中在每個庫中都採用了統一命名方式。API Design Guidleines中包含了這些規則,核心團隊在構建 Swift 3 時採用了這些規則,對新手來說,這高度增強了可讀性和易用性。核心團隊遵循的是”好的 API 設計應當總是從呼叫者的角度看待問題“的原則。他們努力讓 API 簡單易用。不再多說,讓我們開始介紹這些對你來說非常重要的改變。
第一個引數的 label
讓我們從你每天都會在 Swift 中用到的例子開始。
在函式或方法中的第一個引數現在必須有一個 label ,除非你顯式地宣告不要。以前,我們呼叫一個函式或方法時,可以忽略第一個引數的 label[SE-0046]:
<code class="language-swift hljs coffeescript has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">//</span> 第一句是 Swift <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span> 語法,第二句是 Swift <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span> 語法 <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"RW"</span>.writeToFile(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"filename"</span>, <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(0, 136, 0);">atomically</span>: <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">true</span>, <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(0, 136, 0);">encoding</span>: NSUTF8StringEncoding) <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"RW"</span>.write(<span class="hljs-attribute" style="box-sizing: border-box; color: rgb(0, 136, 0);">toFile</span>: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"filename"</span>, <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(0, 136, 0);">atomically</span>: <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">true</span>, <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(0, 136, 0);">encoding</span>: NSUTF8StringEncoding) SKAction.rotateByAngle(CGFloat(M_PI_2), <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(0, 136, 0);">duration</span>: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10</span>) SKAction.rotate(<span class="hljs-attribute" style="box-sizing: border-box; color: rgb(0, 136, 0);">byAngle</span>: CGFloat(M_PI_2), <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(0, 136, 0);">duration</span>: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10</span>) UIFont.preferredFontForTextStyle(UIFontTextStyleSubheadline) UIFont.preferredFont(<span class="hljs-attribute" style="box-sizing: border-box; color: rgb(0, 136, 0);">forTextStyle</span>: UIFontTextStyleSubheadline) override func numberOfSectionsInTableView<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(tableView: UITableView)</span> -></span> Int override func numberOfSections<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> tableView: UITableView)</span> -></span> Int func viewForZoomingInScrollView<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(scrollView: UIScrollView)</span> -></span> UIView? func viewForZooming<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> scrollView: UIScrollView)</span> -></span> UIView? NSTimer.scheduledTimerWithTimeInterval(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0.35</span>, <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(0, 136, 0);">target</span>: self, <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(0, 136, 0);">selector</span>: <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#selector(reset), userInfo: nil, repeats: true)</span> NSTimer.scheduledTimer(<span class="hljs-attribute" style="box-sizing: border-box; color: rgb(0, 136, 0);">timeInterval</span>: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0.35</span>, <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(0, 136, 0);">target</span>: self, <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(0, 136, 0);">selector</span>: <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#selector(reset), userInfo: nil, repeats: true)</span> </code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li></ul>
注意,有些方法使用介詞“of”、“to”、“with”、“in”作為外部引數名。這是為了增加程式碼的可讀性。
如果這個方法不使用介詞也不使用 label,你應該在方法定義時,顯式地在第一個引數名之前加一個下劃線:
<code class="language-swift hljs r has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">...</span> } override func didMoveToView(_ view: SKView) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">...</span> }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul>
在許多程式語言中,許多方法可以共用一個方法名,但引數名不同。Swift 也不例外,現在,你可以過載方法,APIs 能夠將直接將它們轉換成合適的呼叫。下面是一個例子,展示了 index() 方法的兩種過載形式:
<code class="language-swift hljs fsharp has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">let</span> names = [<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Anna"</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Barbara"</span>] <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">let</span> annaIndex = names.index(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">of</span>: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Anna"</span>) { print(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Barbara's position: \(names.index(after: annaIndex))"</span>) }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>
方法名是同一個,但引數名不同,這將讓人更容易記憶。
省略不必要的單詞
過去,在蘋果標準庫中,方法名中會包含一個單詞,用於表明方法的返回值。因為 Swift 編譯支援型別推斷,這種做法其實並不必要。核心團隊儘可能過濾一切“噪音”,因此將這些重複的單詞都刪除了,只留下方法名中最重要的部分。
在將 Objective-C 庫轉換成本地 Swift 語言方面,API 變得更智慧了[SE-0005]:
<code class="language-swift hljs avrasm has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">// 第一句是 Swift <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span> 語法,第二句是 Swift <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span> 語法 let blue = UIColor<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.blueColor</span>() let blue = UIColor<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.blue</span> let min = numbers<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.minElement</span>() let min = numbers<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.min</span>() attributedString<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.appendAttributedString</span>(anotherString) attributedString<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.append</span>(anotherString) names<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.insert</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Jane"</span>, atIndex: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>) names<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.insert</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Jane"</span>, at: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>) UIDevice<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.currentDevice</span>() UIDevice<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.current</span>()</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li></ul>
新的 GCD 和 Core Graphics
一提到遺留下來的“元老級” API,GCG 和 Core Graphics 更需要被重新“裝扮一新”。
Grand Central Dispatch 常用於長時間計算或者與伺服器通訊。將任務放到不同的執行緒,你可以避免阻塞使用者介面。libdispatch 庫是用 C 語言編寫的,提供了 C 風格的 API。這個 API 現在在 Swift 中被重新設計為[SE-0088]:
<code class="language-swift hljs lasso has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Swift 2 語法</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">let</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">queue</span> <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span> dispatch_queue_create(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"com.test.myqueue"</span>, nil) dispatch_async(<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">queue</span>) { print(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Hello World"</span>) } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Swift 3 語法</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">let</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">queue</span> <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span> DispatchQueue(label: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"com.test.myqueue"</span>) <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">queue</span><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>async { print(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Hello World"</span>) }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li></ul>
類似的情況還有 Core Graphics。Core Graphics 是用 C 編寫的,曾經以來一直只能以“醜陋”的函式方式呼叫。這是它的新的用法[SE-0044]:
<code class="language-swift hljs avrasm has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">// Swift <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span> 語法 let ctx = UIGraphicsGetCurrentContext() let rectangle = CGRect(<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">x</span>: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">y</span>: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, width: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">512</span>, height: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">512</span>) CGContextSetFillColorWithColor(ctx, UIColor<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.blueColor</span>()<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.CGColor</span>) CGContextSetStrokeColorWithColor(ctx, UIColor<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.whiteColor</span>()<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.CGColor</span>) CGContextSetLineWidth(ctx, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10</span>) CGContextAddRect(ctx, rectangle) CGContextDrawPath(ctx, <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.FillStroke</span>) UIGraphicsEndImageContext() // Swift <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span> 語法 if let ctx = UIGraphicsGetCurrentContext() { let rectangle = CGRect(<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">x</span>: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">y</span>: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, width: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">512</span>, height: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">512</span>) ctx<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.setFillColor</span>(UIColor<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.blue</span>()<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.cgColor</span>) ctx<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.setStrokeColor</span>(UIColor<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.white</span>()<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.cgColor</span>) ctx<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.setLineWidth</span>(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10</span>) ctx<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.addRect</span>(rectangle) ctx<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.drawPath</span>(using: <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.fillStroke</span>) UIGraphicsEndImageContext() }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li></ul>
列舉中 case 值的大小寫
另一個和過去的 Swift 程式碼不同的地方是,在列舉中定義的 case 值現在使用小駝峰命名法。這是為了和屬性名或者變數名保持一致[SE-0006]:
<code class="language-swift hljs avrasm has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">// 第一句是 Swift <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span> 語法,第二句是 Swift <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span> 語法 UIInterfaceOrientationMask<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Landscape</span> UIInterfaceOrientationMask<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.landscape</span> NSTextAlignment<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Right</span> NSTextAlignment<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.right</span> SKBlendMode<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Multiply</span> SKBlendMode<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.multiply</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li></ul>
大駝峰命名法現在只在型別名和協議名上使用。當你習慣這一切之後,Swift 團隊對於追求一致性的努力才沒有白費。
返回值的方法或者修改值的方法
標準庫中對方法名中使用動詞和名詞的規定也更加統一。你應當根據這個方法會導致什麼後果或者要採取一些動作來進行方法命名。首要原則是如果這個方法名中包含“ed”或“ing”字尾,則表明這是一個名詞。方法名為名詞的方法有返回值。如果不包含這些字尾,則很可能這是一個動詞。以動詞命名的方法會對某塊引用的記憶體進行一些操作。即所謂的“修改某個值”。下面是幾個符合名詞/動詞命名規則的方法[SE-0006]:
<code class="language-swift hljs avrasm has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">customArray<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.enumerate</span>() customArray<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.enumerated</span>() customArray<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.reverse</span>() customArray<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.reversed</span>() customArray<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.sort</span>() // changed from <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.sortInPlace</span>() customArray<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.sorted</span>()</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li></ul>
下面是一些使用這些方法的程式碼片段:
<code class="language-swift hljs livecodeserver has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">var ages = [<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">21</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>]<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"> // 變數,不是常量,這樣你才能修改它</span> ages.<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">sort</span>()<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"> // 修改值,現在值變成了 [2, 10, 21]</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (index, age) <span class="hljs-operator" style="box-sizing: border-box;">in</span> ages.enumerated() {<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"> // "-ed" 是名詞,表示會返回一個 ages 拷貝</span> print(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"\(index). \(age)"</span>)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"> // 列印:1. 2 \n 2. 10 \n 3. 21</span> } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">###函式型別</span> 函式在宣告和呼叫時,都需要用括號將引數括住: ```swift func f(<span class="hljs-operator" style="box-sizing: border-box;">a</span>: Int) { ... } f(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5</span>) <<span class="hljs-operator" style="box-sizing: border-box;">div</span> class=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"se-preview-section-delimiter"</span>></<span class="hljs-operator" style="box-sizing: border-box;">div</span>> </code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li></ul>
但是,當你用函式型別作為引數時,你可能會寫出這樣的程式碼:
<code class="language-swift hljs r has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">func g(a: Int -> Int) -> Int -> Int { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">...</span> } // Swift <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span> 語法 <div class=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"se-preview-section-delimiter"</span>></div> </code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul>
你會發現程式碼很難讀懂。引數在哪裡結束,返回值從哪裡開始?在 Swift 3 中,正確的定義方法是[SE-0066]:
<code class="language-swift hljs r has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">func g(a: (Int) -> Int) -> (Int) -> Int { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">...</span> } // new way, Swift <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span> <div class=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"se-preview-section-delimiter"</span>></div> </code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul>
現在,引數列表被括號包裹,然後才是返回型別。事情變得簡單,同時函式型別更容易被識別出來。通過下面的比照,你會更清楚:
<code class="language-swift hljs lasso has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Swift 2 語法</span> Int <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">-> </span>Float <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">String</span> <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">-> </span>Int T <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">-> </span>U Int <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">-> </span>Float <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">-> </span><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">String</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Swift 3 語法</span> (Int) <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">-> </span>Float (<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">String</span>) <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">-> </span>Int (T) <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">-> </span>U (Int) <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">-> </span>(Float) <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">-> </span><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">String</span> <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;"><</span>div class<span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span><span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"se-preview-section-delimiter"</span><span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">><</span>/div<span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">></span> </code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; paddi