What's new in Swift 3

What's new in Swift 3,第1张

概述原文:What’s New in Swift 3 作者:COSMIN PUPĂZĂ 译者:kmyhy 在 WWDC 大會上,蘋果在 Xcode 8 beta 中集成了 Swift 3,最後的版本則需要到年末的時候才會放出。這是 Swift 開源以後第一個版本,它將同時支持 Mac OS X 和 Linux。如果你關注過去年 11 月份開始的 Swift Evolution 專案,它甚至已經可以在

原文:What’s New in Swift 3
作者:COSMIN PUPĂZĂ
译者:kmyhy

在 WWDC 大會上,蘋果在 Xcode 8 beta 中集成了 Swift 3,最後的版本則需要到年末的時候才會放出。這是 Swift 開源以後第一個版本,它將同時支持 Mac OS X 和 linux。如果你關注過去年 11 月份開始的 Swift Evolution 專案,它甚至已經可以在 IBM sandbox 上運行了,這門語言真的有了天翻地覆的變化。如果你用 Xcode 8 編譯你的專案,你會發現根本無法編譯了。

Swift 3 的改進主要集中在兩個方面:

刪除在 Swift 2.2 中聲明的“已拋棄”特性 讓語言更加“先進”

讓我們先從简单的开始,即 Swift 3 中已刪除的語法特性。這些特性是你在 Xcode 7.3 的中曾經看到過的一些警告。

++ 和 – 運算子

自增、自減運算是從 C 語言中繼承來的,它們的功能很簡單:在某個變量的基礎上減去或加上 1。

var i = 0i++++ii----i

但是,当要选择用这些運算中的哪一個時,往往讓人不知所措。自增和自減運算子都會有兩種使用的方式:前置或後置 ── 它們的實現完全隱藏在底層,返回值對你來說可能有用,也可能無用,幸好我們還有運算子重載。

對於初學者來說,它們太難控制了,因此現在將它們移除了 ── 現在它們完全被 += 和 ﹣= 所替代了:

var i = 0i += 1i -= 1

雖然復合賦值運算要簡短一些,但只要你願意,你也可以用 + 和 ﹣ 運算来達到同樣的目的 :

i = i + 1i = i - 1

[ecko_alert color=”gray”]編後語: 如果你想了解這项改進的最初提議,你可以閱讀Chris Lattner 的關於移除 ++/– 運算子的提議。[/ecko_alert]

C 語言風格的 for 循環成為歷史

對於自增、自減運算用得最多的地方就是 C 語言的經典循環了。當自增、自減運算子被移除后,同時也意味著 C 經典循環的歷史使命被終結了,因為經典循環能做的,用 for-in 循環結合區間的使用同樣能夠做到。

如果你有一定的編程經驗,那麼打印從 1 到 10 的數字你可以用 for 循環來實現:

for (i = 1; i <= 10; i++) { print(i) }

在 Swift 3 中,不再允許這樣做了。下面是 Swift 3 的同一功能的實現 ── 注意,封閉區間運算子 … 的使用:

for i in 1...10 {  print(i)}

此外,你也可以使用 for each 循環和閉包、快捷參數來實現同樣的目的 ── 關於循環的更多討論,請參考這裡。

(1...10).forEach {  print(
func gcd(var a: Int,var b: Int) -> Int {  if (a == b) {    return a  }  repeat {    if (a > b) {      a = a - b    } else {      b = b - a    }  } while (a != b)  return a}
)}

[ecko_alert color=”gray”]編後語: 如果你想了解這項改進的最初提議,請閱讀 Erica Sadun 的關於 C 語言風格的 for 循環的提議 。[/ecko_alert]

函數參數中的 var 被移除

函數參數一般是當做常量來用的,因為在方法中你通常不會修改它們的值。但是某些情況下,你需要將它們聲明為變量。在 Swift 2 中,你可以用 var 來修飾一個函數參數。一旦參數被 var 所修飾,它會創建一份局部變量的拷貝,因此你可以在函數中修改它的值。

例如,下面的函數判斷兩個數字中的最大公約數 ── 如果你忘記了你的高中數學,請你先看這裡:

func gcd(a: Int,b: Int) -> Int {  if (a == b) {    return a  }  var c = a  var d = b  repeat {    if (c > d) {      c = c - d    } else {      d = d - c    }  } while (c != d)  return c}

算法很簡單:如果兩個數字相等,隨便返回其中一個。否則,對二者進行比較,用大的一個減去小的一個并將結果賦給大的一個,直到二者完全相等,最終返回二者之一。如你所見,a 和 b 都用 var 修飾了,因此在函數中我們可以任意改變二者的值。

Swift 3 不再允許這樣做,因為這樣會讓開發者將 var 和 inout 混淆起來。因此新版本中直接不允許在函數參數中使用 var。

因此,gcd 函數需要在 Swift 3 中用其它方式實現。你需要將參數值保存到一個局部變量中:

gcd(8,b: 12)

如果你想了解這項改進的最初提議,請閱讀原始提議。

對函數的參數名一視同仁

函數的參數列表,底層上實際是以元組(tuple)表示的,因此你可以以元組的方式調用函數,就好像調用一個和函數原型相同的元組。以 gcd() 函數為例,你可以這樣調用它:

let number = (8,b: 12)gcd(number)

也可以這樣調用它:

gcd(a: 8,b: 12)

如你所見,在 Swift 2 中第一個參數的 Label(又叫外部參數名)不是必須的。但是,第二個參數的參數名(以及剩餘的其它參數名)則是必須的。

這種語法也會讓新手茫然,因此這次對參數名的使用進行了規範化。在 Swift 3 中,你必須這樣調用這個函數:

func gcd(_ a: Int,b: Int) -> Int {...}

必須顯式地指定第一個參數名。否則,Xcode 8 會提示錯誤。

對此你的第一反應可能是“上帝!這得給我的程式碼帶來多大的修改量!”。你說對了,這個修改量還真不小。因此蘋果提供了一個調用函數時忽略第一個參數名的方法。你可以在第一個參數前面加一個下劃線:

// 1import UIKitimport XCPlayground// 2class Responder: NSObject {  func tap() {    print("button pressed")  }}let responder = Responder()// 3let button = UIbutton(type: .System)button.setTitle("button",forState: .normal)button.addTarget(responder,action: "tap",forControlEvents: .touchUpInsIDe)button.sizetoFit()button.center = CGPoint(x: 50,y: 25)// 4let frame = CGRect(x: 0,y: 0,wIDth: 100,height: 50)let vIEw = UIVIEw(frame: frame)vIEw.addSubvIEw(button)XCPlaygroundPage.currentPage.liveVIEw = vIEw

這樣,你可以不用修改原來的函數調用方式 ── 即不用書寫第一個參數名。這會簡少將程式碼從 Swift 2 升級到 Swift 3 的工作量。

[ecko_alert color=”gray”]編後語: 要了解這項改進的最初提議,請閱讀這個提議。[/ecko_alert]

不能用字符串表示 Selector

讓我們創建一顆按鈕,讓它被觸摸時執行某些動作 ── 假設只能用 playground 而不能用 Interface Builder 實現的話,這段程式碼應當編寫成:

#selector()

程式碼有點多,讓我們將它分成幾步來進行說明:

導入 UIKit 和 XCPlayground 框架 ── 這樣我們才能創建按鈕并將它顯示到 playground 的助手編輯器中。

注意: 通過 VIEw -> Assistant Editor -> Show Assistant Editor 菜單,你可以打開助手編輯器并與按鈕進行交互。

定義一個 tap 方法,這個方法會在用戶觸摸按鈕時觸發,并將一個 responder 對象傳遞給按鈕的 target ── responder 必須繼承自 NSObject,因為 selector 對象只對 Objective-C 方法有效。

創建一個按鈕并設置其屬性。

創建一個視圖,初始化時指定其 frame,然後將按鈕加到 vIEw 上,然後在 playground 的助手編輯器上顯示。

注意突出顯示的程式碼。按鈕的 selector 用一個字符串指定。如果你將這個寫錯了,程式碼仍然能夠編譯,但在運行時會因為找不到相應的方法而崩潰。

為了在編譯時解決這種潛伏的問題,Swift 3 使用

button.addTarget(responder,action: #selector(Responder.tap),for: .touchUpInsIDe)
關鍵字來表示 selector。這樣,如果你寫錯了方法名,編譯器就會提前檢查出問題所在。

class Person: NSObject {  var name: String = ""  init(name: String) {    self.name = name  }}let me = Person(name: "Cosmin")me.valueForKeyPath("name")

[ecko_alert color=”gray”]編後語: 要了解這項改進的最初提議,請閱讀 Doug Gregor 的提議。[/ecko_alert]

上面就是 Swift 中已刪除的語法特性。現在讓我們看一下讓 Swift 更加具有“先進性”的改進有哪些。

Key-paths 不再使用字符串

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

#keyPath()

你創建了一個 Person 類,它是鍵值編碼兼容的,在指定的初始化方法中傳入了我的名字,然後通過 key-path 來讀取我的名字。同樣,如果你把 key-path 弄錯了,app 會崩潰,我會很生氣!:(

幸運的是,Swift 3 解決了這個問題。key-path 字符串現在需要用

class Person: NSObject {  var name: String = ""  init(name: String) {    self.name = name  }}let me = Person(name: "Cosmin")me.value(forKeyPath: #keyPath(Person.name))
表達式來替換:

let file = NSBundle.mainBundle().pathForResource("tutorials",ofType: "Json")let url = NSURL(fileURLWithPath: file!)let data = NSData(contentsOfURL: url)let Json = try! NSJsONSerialization.JsONObjectWithData(data!,options: [])print(Json)

[ecko_alert color=”gray”]編後語: 關於這個改進的最初提議,你可以查看 David Hart 的提議。[/ecko_alert]

Foundation 類型名不再需要 NS 前綴

NS 前綴終於從 Foundation 類型名中移除了 ── 如果你想知道這項改進的最初提議,請看這裡。典型的例子如 JsON 解析:

let file = Bundle.main().pathForResource("tutorials",ofType: "Json")let url = URL(fileURLWithPath: file!)let data = try! Data(contentsOf: url)let Json = try! JsONSerialization.JsonObject(with: data)print(Json)

在將 JsON 數據從文件中讀出的過程中,我們使用了幾個 Foundation 類:
NSBundle -> NSURL -> NSData -> NSJsONSerialization

在 Swift 3 中,NS 前綴被移除了,因此上面的解析過程就變成了:
Bundle -> URL -> Data -> JsONSerialization:

let r =  3.0let circumference = 2 * M_PI * rlet area = M_PI * r * r

[ecko_alert color=”gray”]編後語: 要想知道這項改進的最初提議,請查看 Tony Parker 和 Philippe Hausler 的 這個提議 [/ecko_alert]

M_PI 和 .pi

讓我們用圓半徑算出圓的周長和面積:

float.piDouble.piCGfloat.pi

在老的 Swift 版本中,M_PI 代表了圓周率。Swift 3 中,則將 pi 放到了 float,Double 和 CGfloat 類型的內部:

let r = 3.0let circumference = 2 * Double.pi * rlet area = Double.pi * r * r

因此前面的(計算圓周長和面積)的程式碼,用 Swift 3 則可以編寫為:

let r = 3.0let circumference = 2 * .pi * rlet area = .pi * r * r

由於類型推斷的存在,我們甚至可以忽略類型名,因此代碼可以簡化為:

let queue = dispatch_queue_create("Swift 2.2",nil)dispatch_async(queue) {  print("Swift 2.2 queue")}
GCD

GCD(Grand Central dispath) 通常被用於執行網絡 *** 作而不阻塞主線程中的用戶界面。它是用 C 編寫的,因此它的 API 對於初學者來說難於理解,尤其是想在異步隊列中做某些工作的時候:

let queue = dispatchQueue(label: "Swift 3")queue.async {  print("Swift 3 queue")}

Swift 3 刪除了這些公式化和繁瑣的語法,改用面向對象的方法來實現:

let frame = CGRect(x: 0,height: 50)class VIEw: UIVIEw {  overrIDe func drawRect(rect: CGRect) {    let context = UIGraphicsGetCurrentContext()    let blue = UIcolor.bluecolor().CGcolor    CGContextSetFillcolorWithcolor(context,blue)    let red = UIcolor.redcolor().CGcolor    CGContextSetstrokecolorWithcolor(context,red)    CGContextSetlinewidth(context,10)    CGContextAddRect(context,frame)    CGContextDrawPath(context,.Fillstroke)  }}let aVIEw = VIEw(frame: frame)

[ecko_alert color=”gray”]編後語: 要了解這項改進的最初提議,請閱讀 Matt Wright 的這個提議 [/ecko_alert]

Core Graphics 變得更加“Swift 化”

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

let frame = CGRect(x: 0,height: 50)class VIEw: UIVIEw {  overrIDe func draw(_ rect: CGRect) {    guard let context = UIGraphicsGetCurrentContext() else {      return    }    let blue = UIcolor.blue().cgcolor    context.setFillcolor(blue)    let red = UIcolor.red().cgcolor    context.setstrokecolor(red)    context.setlinewidth(10)    context.addRect(frame)    context.drawPath(using: .fillstroke)  }}let aVIEw = VIEw(frame: frame)

你需要先指定 vIEw 的 frame,繼承 UIVIEw 類,重寫 drawRect 方法以進行定制的繪圖 *** 作,使 vIEw 呈現不一樣的畫面。

Swift 3 中,使用了一種全新的方法來使用 Core Graphic ── 先獲取前繪圖上下文,將它進行解包,解包到一個 context 對象,然後再通過這個 context 來執行所有的繪圖 *** 作:

for i in (1...10).reverse() {  print(i)}

注意: 在 vIEw 調用它的 drawRect 方法之前,圖形上下文為空,因此你需要對其用 guard 語句進行解包 *** 作 ── 更多內容請閱讀這裡。

動詞/名詞命名規範

接下來該講一點語法了!:) Swift 3 將方法分成兩類:有返回值的 ── 使用名詞命名,以及執行某種 *** 作的 ── 使用動詞命名。

下面打印從 10 到 1 的數字:

for i in (1...10).reversed() {  print(i)}

reverse() 方法用於將區間反序。在 Swift 3 看來,這個方法應該用名詞,因為它將原來的區間反向排序后返回。因此,它在這個方法後面加了一個 ed 後綴:

var array = [1,5,3,2,4]for (index,value) in array.enumerate() {  print("\(index + 1) \(value)")}

元組最常用的用法之一,就是打印一個數組的內容:

var array = [1,value) in array.enumerated() {  print("\(index + 1) \(value)")}

在 Swift 3 中,這個方法應該用名詞,因為它也返回了一個由當前數組元素的索引和值共同組成的元組。因此它在這個方法後面也加了一個 ed 後綴:

var array = [1,4]let sortedArray = array.sort()print(sortedArray)

另一個例子是數組的排序。下面我們將一個數組按照升序進行排序:

var array = [1,4]let sortedArray = array.sorted()print(sortedArray)

在 Swift 3 中,這個方法應該使用名詞,因為它返回了經過排序的數組。因此 sort 方法現在被命名為 sorted 方法:

var array = [1,4]array.sortInPlace()print(array)

讓我們直接在數組上進行 *** 作,去掉中間變量。在 Swift 2 中,你會用這樣的程式碼:

var array = [1,4]array.sort()print(array)

你通過 sortInPlace() 方法對一個可變數組排序。Swift 3 中,這個方法名應該用動詞,因為它直接進行實際上的排序 *** 作,而不返回任何東西。只需要用最簡單的單詞就可以描述這種動作。因此 sortInPlace() 應該被 sort() 代替:

XCPlaygroundPage.currentPage

[ecko_alert color=”gray”]編後語: 關於這項命名規範的最初提議,請閱讀 API 設計指南。[/ecko_alert]

API 更加“swift 化”

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

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() 改為 .System 枚舉值

Swift 3 將枚舉值看成屬性,因此使用“小駝峰法”而不是“大駝峰法”進行命名:

.system 改為 .touchUpInsIDe .touchUpInsIDe 改為 .Fillstroke .fillstroke 改為 .CGcolor .cgcolor 改為
overrIDe func vIEwDIDLoad() {    super.vIEwDIDLoad()    printMessage(message: "Hello Swift 3!")}@discardableResultfunc printMessage(message: String) -> String {    let outputMessage = "Output : \(message)"    print(outputMessage)    return outputMessage}
@discardableResult

在 Swift 3 中,如果你不使用方法或函數的返回值,Xcode 會顯示警告,例如:

在上面的程式碼中,printMessage 方法返回一個字符串。但是,這個返回值在我們調用方法的時候沒有用到,這可能引發潛在的問題,因此 Swift 3 編譯器會發出警告。

但是在某些情況下,我們實在是沒有必要保留返回值,因此你可以用一個 @discardableResult 表明方法不需要這種警告:

結束

關於 Swift 3 就介紹到這裡。新的 Swift 版本的發佈,讓這門語言越來越好用啦。在它包含了大量的功能改進的同時,也會對你現在的代碼產生非常大的影響。我希望這篇教程能讓你更好地理解這些改進,同時節省你升級 Swift 專案的時間成本。

本教程中的所有程式碼都可以在 這裡 下載。我已經在 Xcode 8 beta 中通過了測試。請確保你在 Xcode 8 中運行這個專案。

如果你有任何問題和建議,請告訴我。祝你 Coding 快樂! :)

譯者簡介

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

总结

以上是内存溢出为你收集整理的What's new in Swift 3全部内容,希望文章能够帮你解决What's new in Swift 3所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/web/1074321.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-05-26
下一篇2022-05-26

发表评论

登录后才能评论

评论列表(0条)

    保存