Swift 3:你要知道的新特色和改動


在剛完成的WWDC大會上,蘋果發佈了新一代 Swift 3 和 Xcode 8 beta,並預計在本年第四季正式推出。自2015年12月,Swift語言正式開放源代碼,Swift 3 當然也不例外,同時支援 Mac OS X 及Linux 系統。如果你自上年十二月開始追踪 Swift Evolution,或已經曾在 IBM sandbox 試用過的話,或許已經心中有數 Swift 3 有著很大的改動。若果直接在 Xcode 8 上編譯現行的專案,幾乎可以肯定的說不會成功。

Swift 3 的更新主要分為兩個類別:

  • 刪除在 Swift 2.2 中部份過時的功能
  • 優化語言

我們先來看看被移除的部分,這些功能在 Xcode 7.3 時仍然可以使用,只是每當使用時會顯示黃色警告字句。在Swift 3,這些警告字句會變成編譯錯誤。

++ 和 – – 運算子

首先,和大家聊一聊 ++-- 運算子的改動。遞增和遞減運算子從C語言中繼承至 Swift,功能上簡單直接 – 為某個變數增加或減去 1。

然而,這些運算子的使用方法都略有不同,很容易讓人產生混淆。遞增和遞減運算子分別有兩種使用方法:前置或後置 -它們看來相似,但實際運作和結果都大有不同。

對於初學者而言這些都太複雜難懂了,所以在Swift 3都統統移除 – 由增加 (+=) 和 減去 (-=) 取而代之:

當然,你也可以使用增加 (+) 和減去 (-) 運算子,雖然複合指派運算子的做法會更簡短:

伸延閱讀: 如果你想了解更多關於這個改動背後的動機,請參考 Chris Lattner 移除 ++/– 運算子的建議

C 語言風格的 for 迴圈語法成為歷史

遞增和遞減運算子經常出現在C語言的迴環語法,當遞增和遞減運算子被移除,意味著唇齒相依的 for 迴環也走到末路,往後將會以更簡潔的 for-in 控制流程敍述實現相樣的功能。

假設你對編程有基本經驗,大概也會使用 for 迴環來列出1-10:

由 Swift 3 開始,就不再允許這種做法。優化後的程式碼將會如下 - 注意這是封閉範圍運算子 (…) 的使用:

另外,你也可以使用 for-each 迴環加以閉包和縮寫參數 - 關於迴環的更多資料,請參閱這裡

伸延閱讀: 如果你想了解更多關於這個改動背後的動機,請參考 Erica Sadun 關於棄用 C 語言風格的 for 循環的提議

函式參數中移除 var

函式參數一般會定義為常數,當你不需要修改它的值。但是,有時候為了使用上方便就會定義為變數。在Swift 2,你可以使用 var 把函式參數定義為變數。當參數被定義為 var,它會本地複製值,使你可以在函數中修改值。

舉例,以下的功能測定兩個數字的最大公因數 - 若果你忘記了什麼是最大公因數,可以到這裡重溫

算法很簡單:如果兩個數字相等,返回其中一個。相反,將二者進行比較,用大數字一個減去小數字,並將結果賦於大數字,直到二者完全相等,最終返回二者之一。如你所見,a 和 b 都是變數,因此我們都可以更改它們的值。

Swift 3 為免 Swift 開發者容易混淆 varinout,故此不再允許把函式參數設置成變數。 而最新版本的 Swift 裡也把 var 從函式參數中刪除。

因此,在 Swift 3 要用上不同的方法去尋找最大公因數。你需要將函式參數儲存到一個本地變數中:

伸延閱讀: 如果你想了解更多關於這個改動背後的動機,請參考原本建議

函式參數的一致標記特性

函式參數列實際上由元組表示,所以我們可以使用元組呼叫函數,就好像以元組結構配對函數原型。以 gcd() 功能為例。你可以這樣呼叫它:

也可以這樣調用它:

如你所見,在 Swift 2 中你不需要指定第一個參數標記,但需要為第二個(或其餘的)參數指定標記。

對菜鳥來說這個語法應該挺複雜,因此優化後對參數標記的使用進行了規範化。在 Swift 3, 你可以這樣呼叫函數:

你必須明確指定第一個參數的標記。否則,Xcode 8 會提示出現錯誤。

這個改動意味著有大量的程式碼需要修改。沒錯,確實有很多修改的地方。因為蘋果提供了一個呼叫函數時忽略第一個參數標記的方法。這就是把下劃線添加到第一個參數之前:

通過這個方法,你可以沿用舊的方法調用函數 - 不用指定第一個標記。這將使你較輕易地把程式碼由 Swift 2 轉移至 Swift 3。

伸延閱讀: 如果你想了解更多關於這個改動背後的動機,請參考這個提議

不能再用字串來表示選擇器 (Selectors)

當我們要建立一個按鈕並讓它被觸及時執行某些動作 - 假設只能使用 playground 而沒有在 Interface Builder 實現:

程式碼頗長,讓我們將它分成幾步來進行說明:

  1. 導入 UIKit 和 XCPlayground 框架 - 我們需要利用這些去建立按鈕,並把它顯示到 playground 的助理編輯器。
注意: 你可以從這個途徑去把Xcode的助理編輯器打開:View > Assistant Editor > Show Assistant Editor。
  1. 為 tap 方法定義,當用戶點擊按鈕便會觸發這個方法,並把一個回應物件回傳給按鈕目標 - 這需要堅於一個 NSObject,因為選擇器只對 Objective-C 方法有效。

  2. 宣告按鈕並設置其屬性。

  3. 宣告視圖及其相應的資訊框,在視圖添加一個按鈕,然後在 playground 的助理上顯示出來。

看看以黃色突出顯示的程式碼。按鈕選擇器是一個字串。若果你錯誤輸入的話,當程式執行時,程式碼便會出現問題,因為找不到相應的方法而導致程式錯誤彈出。

要解決這個編譯時潛在問題, Swift 3 使用了 #selector() 關鍵字取代了選擇器。這樣編譯器能夠及早偵查到相關問題之所在。

伸延閱讀: 如果你想了解更多關於這個改動背後的動機,請參考 Doug Gregor 的提議

以上就是 Swift 3 已移除的語法特性。現在讓我們看一下讓 Swift 3 優化後的亮點。

Key-paths 是字串

這個特性跟前一個有點相似,但它被使用於 kvc (鍵值編碼)和 kvo (鍵值觀察)。

你建立了一個鍵值編碼兼容的 Person 類別,在類別指定初始化中建立名字,使用通過鍵值來讀取名字。同樣,若果在這部份輸入錯誤,Swift 3 會顯示警句字句,可以把 key-path 字串寫成為 #keyPath() 來表達式來替換:

伸延閱讀: 如果你想了解更多關於這個改動背後的動機,請參考 David Hart 的提議

Foundation 型態不再需要 NS 字首

NS 字首從 Foundation 型態中移除了 - 若果想重溫 NS 是什麼,可以查看這裡。一個 JSON 剖析的典型例子:

你可以使用 Foundation 類別去連接檔案,並以這個方法提取 JSON 數據:NSBundle > NSURL > NSData > NSJSONSerialization

在 Swift 3 中,NS 字首被移除了,因此上面的剖析過程就變成這樣:Bundle > URL > Data > JSONSerialization:

伸延閱讀: 如果你想了解更多關於這個改動背後的動機,請參考 Tony Parker 和 Philippe Hausler 的 這個提議

M_PI vs .pi

讓我們利用已知的半徑去計算圓週和圓的面積:

在以往的 Swift 版本中,M_PI 代表了圓周率常數。在 Swift 3,pi 常數被整合為 Float, Double 和 CGFloat 類型:

上述的程式碼在 Swift 3 轉變成這樣子:

基於型態推斷,你可以忽略型態,因此程式碼可以簡化為:

Grand Central Dispatch

Grand Central Dispatch (GCD) 常用於網絡操作但不阻礙主執行緒的使用者介面。它是由 C 所編寫,因此初學者較難去理解它的 API,即使建立一個瑣細任務如非同步佇列並使它做點事情:

Swift 3 刪除了所有樣版程式碼和冗餘的語法,改為使用物件導向方法:

伸延閱讀: 如果你想了解更多,請參考 Matt Wright 的這個提議

Core Graphics 變得更 「Swift 化」

Core Graphics 是一個強大的繪圖框架,但使用了跟 GCD 一樣的 C 風格 API:

你需要建立一個視圖資訊框,伸延 UIView 類別,覆寫 drawRect() 方法以進行自定繪圖,並使視圖展示新的內容。

來到 Swift 3 將會用上煥然一新的方法 - 首先打開現時圖像內容,然後執行所有繪圖有關操作:

注意:在視圖呼叫 drawRect() 方法之前,內容是空白的,所以你需要使用 guard 敍述去打開它 - 按此了解更多。

動詞 VS 名詞命名規約

Swift 3 將方法分成兩個組別:有返回值的 - 把它們當作名詞;以及執行某種動作的方法 - 把它們當作動詞。

以下是以現有 Swift 程式碼把 10 到 1 的數字列出來:

上述使用了 reverse() 方法把數字順序倒轉,而在 Swift 3 就會在方法後置 “ed”:

元組中最常用的是列出陣列內容:

Swift 3 中就需要為 enumerate() 加上 “ed”:

另一個例子是陣列排序。下面我們將以現時的 Swift 程式碼為陣列按升序排序:

轉換成 Swift 3,sort 方法改為 sorted:

把陣列直接排序,不使用中間常數。現時我們寫的程式碼像這樣:

使用 sortInPlace() 去為一個可變的陣列排序。在 Swift 3,這個方法像一個動詞般使用,讓它執行實執排序動作而不需要返回任何東西。它使用最基本的單詞去形容動作。所以 sortInPlace() 被 sort() 取代:

伸延閱讀: 如果你想了解更多,請參考 API 設計指南

優化 API

Swift 3 使用了一個簡單的哲學來規範其 API - 刪除冗餘的單詞,如果某個單詞是多餘的或者是能夠通過上下文推斷出來的,便會被刪除:

  • XCPlaygroundPage.currentPage 改為 PlaygroundPage.current
  • button.setTitle(forState) 改為 button.setTitle(for)
  • button.addTarget(action, forControlEvents) 改為 button.addTarget(action, for)
  • NSBundle.mainBundle() 改為 Bundle.main()
  • NSData(contentsOfURL) 改為 URL(contentsOf)
  • NSJSONSerialization.JSONObjectWithData() 改為 JSONSerialization.jsonObject(with)
  • UIColor.blueColor() 改為 UIColor.blue()
  • UIColor.redColor() 改為 UIColor.red()

列舉 Cases

Swift 3 例舉 cases 如像屬性,因此使用 「lowerCamelCase」 而不是「upperCamelCase」 進行命名:

  • .System 改為 .system
  • .TouchUpInside 改為 .touchUpInside
  • .FillStroke 改為 .fillStroke
  • .CGColor 改為 .cgColor

@discardableResult

在 Swift 3 中,若果你不使用一個函數或方法的返回值,Xcode 將會給予你警告。例如:

discardable-result-1

在上述的程式碼,printMessage 方法返回了一個訊息。但是,並沒有使用返回值。這裡可能引發潛在的問題,所以我Swift 3 會發出警告。

在某些情況下,並不是強制要求返回值。我們可以宣告 @discardableResult 方法繞過這個警告:

結語

這些都是 Swift 3 的簡介。新版本 Swift 有大量的改動,讓它得到優化和改善之餘,同時為現時的 Swift 程式碼帶來重大的影響。我希望這篇教程能夠讓你更清楚這些改動,也期望這些能夠節省你遷移 Swift 專案的時間。

本教程中的所有程式碼都可以在這裡下載。這些程式碼我都已經親身試驗過,確保在 Xcode 8 beta 中能夠順利執行。

如果有任何疑問或困難,歡迎留言查詢。

譯者簡介:楊宏焱,CSDN 博客專家(個人博客 http://blog.csdn.net/kmyhy)。2009 年開始學習蘋果 iOS 開發,精通 O-C/Swift 和 Cocoa Touch 框架,開發有多個商店應用和企業 App。熱愛寫作,著有多本技術專著,包括:《企業級 iOS 應用實戰》、《iPhone & iPad 企業移動應用開發秘笈》、《iOS8 Swift 編程指南》,《寫給大忙人看的 Swift》(合作翻譯)等。

原文What’s New in Swift 3


Cosmic Pupăză 在部落格 cosminpupaza.wordpress.com 分享有關 Swift 和 iOS 開發文章,以及參與了 raywenderlich.com 和 appcoda.com 兩個平台的 Swift 教學團隊。平日喜歡玩結他和研究二戰歷史。可以透過電郵:cosminpupaza@gmail.com,在Facebook,Twitter 及 Google+ 找到 Cosmic。

blog comments powered by Disqus
訂閲電子報

訂閲電子報

AppCoda致力於發佈優質iOS程式教學,你不必每天上站,輸入你的電子郵件地址訂閱網站的最新教學文章。每當有新文章發佈,我們會使用電子郵件通知你。

已收你的指示。請你檢查你的電郵,我們已寄出一封認證信,點擊信中鏈結才算完成訂閱。

Shares
Share This