Swift 3 新特性

WhatsNewSwift3-feature-250x250500.jpg

原文:What's New in Swift 3? ,做者:Ben Morrow,譯者:kmyhyhtml

Swift 3將於今年下半年推出,爲Swift開發者們帶來了不少核心代碼的改變。若是你沒有關注過 Swift Evolution 項目,你可能會好奇Swift 3中有什麼改變,它會對你的代碼帶來什麼影響,以及什麼時候能夠將代碼移植到Swift 3。本文就將爲你答疑解惑!ios

本文中,我將重點介紹 Swift 3 中的重大改變,以及這些改變對你的代碼的深入影響。讓咱們開始吧!git

開始程序員

目前,Swift 3 預覽版僅在 Xcode 8 beta版中可用。在將來幾個月中,Swift 3 仍然在不斷改變中,它還會發生一些變化。在 2016 年底,Xcode GM 發佈時,Swift 3 的新特性纔會穩定。因此各位開發者要沉住氣,直到那個時候才能夠向 App Store 提交用 Swift 3 編寫的 App。github

爲了便於開發者們將代碼遷移到 Swift 3,蘋果在 Xcode 8 中增長了一個 Swift 版本,即 Swift 2.3,對 Swift 做了一個小小的升級。若是你是一個開發者,Swift 2.3 和 2.2 實際並沒有不一樣,但 Swift 2.3版本可以支持本次WWDC中提到的各類新的SDK 和 Xcode 特性。在 Xcode 8 推出 beta 版時,你能夠用 Swift 2.3 來提交你的 app,而不用將代碼遷移到 Swift 3。objective-c

我建議你在 Playground 中測試本文討論的新特性,還能夠用你的某個項目來測試 Migration Assistant,以便你對這些改變有所瞭解。因爲在 Xcode 8 beta 下一個版本及 Siwft 3 正式發佈以前,你沒法向 App Store 提交 App,那麼我建議暫時先不要講代碼遷移到Swift 3。算法

升級到 Swift 3編程

升級到Swift 3時,你會發現基本上每一個文件都須要改動!之因此這樣,是由於全部的 Cocoa API 名稱都改變了。簡而言之,API仍是原來的 API,但這個 API 在 Objective-C 中是一種叫法,而在 Swift 中是另外一種叫法。Swift 3的語法書寫起來要更貼近於天然語言。swift

在Xcode 8中,蘋果提供了Migration Assistant,它能夠完成大部分的遷移工做。固然,仍然有一部分工做是須要你手動完成的。api

你能夠當即將代碼升級到 2.3 或者 3.0。若是你須要將代碼又轉回來,你能夠用 Xcode 的 Edit > Convert > To Current Swift Syntax… 菜單。編譯器會和 Migrateion Assistant 同樣智能。若是你在調用方法時,偶然使用了老的 API,編譯器會顯示一個 Fixt-It 選項,讓你使用正確的新 API。幸虧 Swift 3 在最終發佈時,纔會中止改變源代碼。所以,你能夠將你的 Swift 代碼保存爲不一樣的版本。可是 Swift 核心團隊不能保證這一點之後不會改變,若是在某個時候不在保證源碼上的兼容,他們會提供一個較長的過渡期。這意味着源碼是穩定的,這樣能鼓勵更多的保守的公司去使用它。

這也說明,二進制穩定的目標尚未達到。本文最後將討論這將致使的影響。

已實現的 Swift Evolution 提議

自從 Swift 開源以來,社區成員已經提交了超過 100 個改進建議。其中大部分(70多個)提議通過討論修改以後已經被接受。還有一些仍然在激烈的爭論以後被拒絕了。但最終,全部提議都要通過核心團隊的最終拍板。

核心團隊和廣大社區之間的合做是卓有成效的。事實上,Swift 在 Github 上得到了 30,000 多顆星。每週都會有新的提議提交,週週如此。甚至蘋果的工程師也會在 Github 上提交他們的提議。

在下一節中,你會看到一些相似 [SE-0001] 這樣的標註。這是已經接受的提議編號,而且將在最終版的 Swift 3.0 中進行實現。每項提議都會標出,以便你查看每項改變的具體細節。

API 的改變

Swift 3 中最大的改變是標準庫中在每一個庫中都採用了統一命名方式。API Design Guidleines中包含了這些規則,核心團隊在構建 Swift 3 時採用了這些規則,對新手來講,這高度加強了可讀性和易用性。核心團隊遵循的是"好的 API 設計應當老是從調用者的角度看待問題"的原則。他們努力讓 API 簡單易用。再也不多說,讓咱們開始介紹這些對你來講很是重要的改變。

第一個參數的 label

咱們以一個開發者天天都會在 Swift 中用到的例子開始。

 

在函數或方法中的第一個參數如今必須有一個 label ,除非你顯式地聲明不要。之前,咱們調用一個函數或方法時,能夠忽略第一個參數的 label[SE-0046]:

// old way, Swift 2, followed by new way, Swift 3
"RW".writeToFile("filename", atomically: true, encoding: NSUTF8StringEncoding)
"RW".write(toFile: "filename", atomically: true, encoding: NSUTF8StringEncoding)
SKAction.rotateByAngle(CGFloat(M_PI_2), duration: 10)
SKAction.rotate(byAngle: CGFloat(M_PI_2), duration: 10)
UIFont.preferredFontForTextStyle(UIFontTextStyleSubheadline)
UIFont.preferredFont(forTextStyle: UIFontTextStyleSubheadline)
override func numberOfSectionsInTableView(tableView: UITableView) -> Int
override func numberOfSections(in tableView: UITableView) -> Int
func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView?
func viewForZooming(in scrollView: UIScrollView) -> UIView?
NSTimer.scheduledTimerWithTimeInterval(0.35, target: self, selector: #selector(reset), userInfo: nil, repeats: true)
NSTimer.scheduledTimer(timeInterval: 0.35, target: self, selector: #selector(reset), userInfo: nil, repeats: true)

  

注意,有些方法使用介詞"of"、"to"、"with"、"in"做爲外部參數名。這是爲了增長代碼的可讀性。

若是這個方法不使用介詞也不使用 label,你應該在方法定義時,顯式地在第一個參數名以前加一個下劃線:

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { ... }
override func didMoveToView(_ view: SKView) { ... }

  

在許多編程語言中,許多方法能夠共用一個方法名,但參數名不一樣。Swift 也不例外,如今,你能夠重載方法,APIs 可以將直接將它們轉換成合適的調用。下面是一個例子,展現了 index() 方法的兩種重載形式:

let names = ["Anna", "Barbara"]
if let annaIndex = names.index(of: "Anna") {
print("Barbara's position: \(names.index(after: annaIndex))")
}

  

方法名是同一個,但參數名不一樣,這將讓人更容易記憶。

省略沒必要要的單詞

在早期的蘋果標準庫中,方法名中會包含一個單詞,用於代表方法的返回值。由於 Swift 編譯支持類型推斷,這種作法其實並沒必要要。核心團隊儘量過濾一切"噪音",所以將這些重複的單詞都刪除了,只留下方法名中最重要的部分。

 

在將 Objective-C 庫轉換成本地 Swift 語言方面,API 變得更智能了[SE-0005]:

// old way, Swift 2, followed by new way, Swift 3
let blue = UIColor.blueColor()
let blue = UIColor.blue()
let min = numbers.minElement()
let min = numbers.min()
attributedString.appendAttributedString(anotherString)
attributedString.append(anotherString)
names.insert("Jane", atIndex: 0)
names.insert("Jane", at: 0)
UIDevice.currentDevice()
UIDevice.current()

  

 

新的 GCD 和 Core Graphics

一提到遺留下來的「元老級」API,GCG 和 Core Graphics 更須要被從新「裝扮一新」。

 

Grand Central Dispatch 經常使用於長時間計算或者與服務器通信。將任務放到不一樣的線程,你能夠避免阻塞用戶界面。libdispatch 庫是用 C 語言編寫的,提供了 C 風格的 API。這個 API 如今在 Swift 中被從新設計爲[SE-0088]:

// old way, Swift 2, followed by new way, Swift 3
let blue = UIColor.blueColor()
let blue = UIColor.blue()
let min = numbers.minElement()
let min = numbers.min()
attributedString.appendAttributedString(anotherString)
attributedString.append(anotherString)
names.insert("Jane", atIndex: 0)
names.insert("Jane", at: 0)
UIDevice.currentDevice()
UIDevice.current()

  

相似的狀況還有 Core Graphics。Core Graphics 是用 C 編寫的,曾經以來一直只能以"醜陋"的函數方式調用。這是它的新的用法[SE-0044]:

// old way, Swift 2
let ctx = UIGraphicsGetCurrentContext()
let rectangle = CGRect(x: 0, y: 0, width: 512, height: 512)
CGContextSetFillColorWithColor(ctx, UIColor.blueColor().CGColor)
CGContextSetStrokeColorWithColor(ctx, UIColor.whiteColor().CGColor)
CGContextSetLineWidth(ctx, 10)
CGContextAddRect(ctx, rectangle)
CGContextDrawPath(ctx, .FillStroke)
UIGraphicsEndImageContext()
// new way, Swift 3
if let ctx = UIGraphicsGetCurrentContext() {
    let rectangle = CGRect(x: 0, y: 0, width: 512, height: 512)
    ctx.setFillColor(UIColor.blue().cgColor)
    ctx.setStrokeColor(UIColor.white().cgColor)
    ctx.setLineWidth(10)
    ctx.addRect(rectangle)
    ctx.drawPath(using: .fillStroke)
    UIGraphicsEndImageContext()
}

  

枚舉中 case 值的大小寫

另外一個和過去的 Swift 代碼不一樣的地方是,在枚舉中定義的 case 值如今使用小駝峯命名法。這是爲了和屬性名或者變量名保持一致[SE-0006]:

//old way, Swift 2, followed by new way, Swift 3
UIInterfaceOrientationMask.Landscape
UIInterfaceOrientationMask.landscape
NSTextAlignment.Right
NSTextAlignment.right
SKBlendMode.Multiply
SKBlendMode.multiply

  

UpperCamelCase命名法如今只在類型名和協議名上使用。當你習慣這一切以後,Swift團隊對於追求一致性的努力纔沒有白費。

返回值的方法或者修改值的方法

標準庫中對方法名中使用動詞和名詞的規定也更加統一。你應當根據這個方法會致使什麼後果或者要採起一些動做來進行方法命名。首要原則是若是這個方法名中包含"ed"或"ing"後綴,則代表這是一個名詞。方法名爲名詞的方法有返回值。若是不包含這些後綴,則極可能這是一個動詞。以動詞命名的方法會對某塊引用的內存進行一些操做。即所謂的"修改某個值"。下面是幾個符合名詞/動詞命名規則的方法[SE-0006]:

customArray.enumerate()
customArray.enumerated()
customArray.reverse()
customArray.reversed()
customArray.sort() // changed from .sortInPlace()
customArray.sorted()

  

下面是一些使用這些方法的代碼片斷:

var ages = [21, 10, 2] // 變量,不是常量,這樣你才能修改它
ages.sort() // 修改值,如今值變成了 [2, 10, 21]
for (index, age) in ages.enumerated() { // "-ed" 是名詞,表示會返回一個 ages 拷貝
print("\(index). \(age)") // 打印:1. 2 \n 2. 10 \n 3. 21
}

  

函數類型

函數在聲明和調用時,都須要用括號將參數括住:

func f(a: Int) { ... }
f(5)

  

可是,當你用函數類型做爲參數時,你可能會寫出這樣的代碼:

func g(a: Int -> Int) -> Int -> Int  { ... } // old way, Swift 2

  

你會發現代碼很難讀懂。參數在哪裏結束,返回值從哪裏開始?在 Swift 3 中,正確的定義方法是[SE-0066]:

func g(a: Int -> Int) -> Int -> Int  { ... } // old way, Swift 2

  

如今,參數列表被括號包裹,而後纔是返回類型。事情變得簡單,同時函數類型更容易被識別出來。經過下面的比照,你會更清楚:

// old way, Swift 2
Int -> Float
String -> Int
T -> U
Int -> Float -> String
// new way, Swift 3
(Int) -> Float
(String) -> Int
(T) -> U
(Int) -> (Float) -> String

  

API中新增功能

除了對已有 API 進行「舊瓶新裝」這個最大的改變之外--有很是多的 Swift 社區正致力於此,也有對 Swift API 的一些功能上的增長。

訪問所屬類型

當你定義一個靜態屬性或方法時,你直接經過類或類型來調用它們:

CustomStruct.staticMethod()

  

若是你當前正在編寫類型內部的代碼,仍是要使用類型名來調用靜態方法。爲了使表述更加清晰,如今你能夠經過 Self 來引用當前實例所屬類型。S 爲大寫的 Self 表示引用當前實例的類型,而 s 爲小寫的 self 則引用當前實例自身。

 

這是具體的例子[SE-0068]:

struct CustomStruct {
  static func staticMethod() { ... }
  func instanceMethod() {
    Self.staticMethod() // in the body of the type
  }
}
let customStruct = CustomStruct()
customStruct.Self.staticMethod() // on an instance of the type

  

行內Sequences

sequence(first:next:) 以及 sequence(state:next:) 是全局函數,返回一個無限序列。你傳給它們一個初值或一個可變的狀態,它們會在稍後調用閉包中的代碼[SE-0094]:

for view in sequence(first: someView, next: { 0.superview }) {
// someView, someView.superview, someView.superview.superview, ...
}

  

還能夠用 prefix 操做符來爲序列加一個限制[SE-0045]:

for x in sequence(first: 0.1, next: { 0 * 2 }).prefix(while: { 0 < 4 }) {
// 0.1, 0.2, 0.4, 0.8, 1.6, 3.2
}

  

雜項

  • keyPath() 等同於 #selector() ,幫助你減小輸入錯誤

  • 你能夠在某些類型上調用 pi,好比:Float.pi、CGFloat.pi。大部分時候編譯器可以推斷出類型:let circumference = 2 * .pi * radius [SE-0067]

  • NS 前綴從老的 Foundation 類型中移除,如今能夠用 Calendar、Date來替代 NSCalendar、NSDate 了

工具的改善

Swift 只是一門語言,大部分時候你都沒法離開書寫它的開發環境--對於蘋果開發者來講,也就是 Xcode!工具上的改變影響着天天編寫代碼的方式。

Swift 3 修正了編譯器和 IDE 中的 Bug,還改善了報告錯誤和信息的精確性。就像你所指望的,每一個版本的發佈都會讓 Swift 和編譯器的運行變得更快:

  • 改善了字符串的 Hash 算法,致使在將字符串存入字典後,性能有 3 倍的提高

  • 將對象從堆移到棧中存放,致使性能有 24 倍的提高(某些狀況下)

  • 編譯器能夠一次緩存多個文件(在整個模塊被優化過的狀況下)

  • 優化了代碼的大小,致使 Swift 代碼的編譯尺寸更小。以蘋果的 Demobots 爲例,編譯尺寸縮減了原大小的 77%。

Xcode 也會更加智能地理解 Swift 代碼:

  • 過去,當你在一個 API 方法好比 sort() 上右擊並跳轉到定義時,你會看到一個不太容易理解的頭文件。如今,在 Xcode 8 中,你會看到 sort() 方法其實是 Array 類的擴展。

  • Swift Snapshots就現在晚發佈的 Swift Evolution 所說。在徹底合併到 Xcode 以前,Snapshots 提供了一個使用新語法的機會。Xcode 8 可以在 playgournd 中加載和運行 Swift Snapshots。

Swift 包管理器

開源後的 Swift 實際上包含了 Swift 語言自己、核心庫和包管理器。這三者一塊兒構成了咱們所見到的 Swift。Swift 包管理器定義了一個簡單的目錄結構,其中包括了你所共享和導入到項目中的 Swift 代碼。

相似於你所用過 Cocoapods 或 Carthage 這些包管理器,Swift 包管理器會下載依賴項並編譯它們,把它們 link 成庫或可執行文件。已經有 1000 個庫支持 Swift 包管理器,而且在將來幾個月中,還會有更多的庫支持它。

計劃中的特性

前面說過,Swift 3 儘可能避免不兼容的改變,從而使你的代碼可以從一個版本與下一個版本兼容。若是這是真的,那麼在此次發佈中應該還有一些更遠大的目標未能達到,即泛型加強(generic additions)和 ABI(程序二進制接口)穩定。

泛型加強包括遞歸協議約束和可以將一個受約束的擴展符合新協議(例如,一個用於存放 Equatable 對象的數組也應當遵照 Equatable 協議)。在這些特性還沒有實現以前,Swift 不能被視做 ABI 穩定的。

ABI 穩定要求應用程序和庫不管使用哪一個版本的編譯器編譯,都能被 link 和可以彼此進行交互。這對於第三方庫來講是個重要的進步,由於這樣就能夠不須要提供源碼就能夠封裝出框架了,而如今新版本的 Swift 不但要這些第三方庫修改代碼,還要從新進行編譯。

此外,若是 ABI 穩定就能夠移除包含在二進制文件中的 Swift 標準庫,由於就目前來講 iOS 和 macOS APP都是用 Xcode 建立的。目前的二進制文件中包含有 2 MB 左右的文件大小是爲了確保可以兼容將來的操做系統。

總之,你如今只能保持源代碼的版本兼容,而二進制版本的兼容當前仍然是不可能的。

結尾

Swift 仍然在不斷演進,由於社區的目標是最佳實踐。雖然它還很年輕,但它同時也面臨着無比巨大的機遇和美好將來。Swift 如今已經可以在 Linux 上運行了,在將來幾年,你還會看見它在更多的服務器和設備上運行。從頭設計一門語言必然會破壞 ABI 穩定性,一旦等它穩定後這種破壞就變得小多了。這(開源)是惟一可以讓這門語言變得更好的機會,不然咱們必將後悔莫及。

Swift 正在擴大它的影響力。蘋果正在身體力行。蘋果的團隊們正在 Music app、Console、Sierra畫中畫、Xcode 文檔查看器、新的 iPad 版的Swift Playground app 中使用 Swift。

說到這裏,蘋果好像有一種讓非程序員學習 Swift 意圖,例如能夠在 iPad 上使用 Swift 以及某些教育措施都代表了這一點。

另外,Swift 正在持續改進:命名變得更規範,代碼讀起來更清晰,你能夠用工具來遷移代碼。若是你想進一步深刻了解,請看WWDC 的會議視頻

能夠確定的是,2016年底 Swift 3 的正式發佈必將使人期待。咱們將持續跟進全部改變,請繼續關注咱們的教程、新書預告和視頻,咱們將開始使用這些使人興奮的改進。

 

本文轉自:http://www.cocoachina.com/swift/20160712/17028.html

相關文章
相關標籤/搜索