Swift 3帶來的新變化

624313247 8年前發布 | 35K 次閱讀 Swift Apple Swift開發

今年下半年,Swift 3 就要正式發布了。對于任何一位 Swift 開發人員來說,都會給其代碼帶來很大的改變。

如果還沒有密切關注過 Swift Evolution   的話,你可能會好奇究竟引入了什么新內容,這些新內容會如何影響自己的代碼,還有什么時候要把代碼轉換成 Swift 3 版本,本文會回答這些問題!

在這篇文章中,我將重點闡述 Swift 3 中會給代碼帶來影響的最重要的變化。就讓我們來一探究竟吧!

開始遷移

今天 Swift 3 預覽版在 Xcode 8 Beta 上可以使用了,Swift 3 的演進過程即將落幕。在未來幾個月內仍然可能會有一些變化。2016 年底,Xcode GM 版(測試版的一種,屬于如果沒有發現問題就作為正式版發布的版本。一般情況下 GM 版隨后都會變為正式版發布,所以也有人在正式版發布之前將 GM 版當正式版安裝使用)誕生的時候,Swift 3 的功能特性就會穩定下來。所以我們要把 Swift 3 編寫的 App 推遲到那個時候再發布到 App Store。

為了讓開發人員能夠自己遷移到 Swift 3,蘋果公司已經將 Swift 2.3 作為小的更新與 Xcode 8 捆綁在一起了。對于開發人員來說,Swift 2.3 與 Swift 2.2 比較,前者支持很多在 WWDC 上宣布的新的 SDK,還有 Xcode 新的功能特性。一旦 Xcode 8 的 beta 版發布,又沒有把代碼遷移到 Swift 3 的話,那么我們就可以使用 Swift 2.3 開發并提交應用了。

我建議在 playground 里嘗試一下我們在討論的新特性,還可以使用蘋果的 Migration Assistant 功能,把一切更改都直接拿過來用。但是由于 Xcode 8 要升級到 beta 版本,或者要等到 Swift 3 最終發布出來,否則我們無法向 App Store 提交 App,所以我們可能會等到這一切都定下來以后,才會把代碼遷移到 Swift 3。

遷移代碼到 Swift 3

將代碼遷移到 Swift 3 的時候,你會發現幾乎每個文件都需要修改!很大程度上是由于所有 Cocoa API 的名稱都已經發生了變化。更確切地說,API 是一樣的,一個名字用于 Objective-C,另一個名字用于 Swift。未來幾年,Swift 3 的風格會變得更自然。

蘋果的 Migration Assistant 功能可以出色地一次性搞定這些變化。雖然有些地方在遷移的過程中無法自動進行處理,需要我們自己修改,但這是很正常的事情。

我們可以直接將代碼轉化為 Swift 2.3,也可以轉化為 Swift 3。如果想要回到之前的某個版本,可以在 Xcode 中使用 Edit> Convert > To Current Swift Syntax…來做版本轉換。幸運的是,這個功能像 Migration Assistant 一樣智能。如果我們不小心調用了舊有的 API,編譯器會給出“Fix-It”這樣的提示,可以幫助我們使用當前正確的 API。

最好的消息是 Swift 3 旨在成為源碼級修改的最終版本。展望未來,我們應該能夠避免對 Swift 代碼做版本轉換。雖然Swift語言的核心開發團隊無法對未來的變化作出預測,但他們已經承諾,如果要打破源碼的兼容性的話,他們會對舊有的 API 提供較長的棄用時間。這也就意味著 Swift 達到源碼穩定的程度,會鼓勵更多思想保守的公司盡可能地去使用。

這也同時表明,Swift 語言還沒有達到二進制源碼穩定的程度。讀完這篇文章以后,你會發現這種不穩定性帶來的更多影響。

已經實施的 Swift 語言的改進建議

自從 Swift 開源以來,開發者社區的成員已經提交超過 100 份修改意見。大量(迄今為止 70 項)的修改意見經過討論和修改后被采納。但也有一些被駁回的建議引發了激烈的討論。最后,核心開發團隊對所有建議做出最終的決定。

Swift 核心開發團隊與廣大的開發者社區之間的合作令人印象深刻。事實上,Swift 項目在 GitHub 已經獲得了 3 萬顆 star。每一周都有新的修改意見被提交,周而復始。蘋果開發工程師甚至把要修改的內容在 GitHub 上創建開放的 repository。

在本文接下來的章節中,我們會看到帶有[SE-0001]標簽樣子的鏈接。這些數字都是 Swift Evolution 的編號。這里是已經被采納的修改建議,在最終版本 Swift 3.0 中會被實現。每項修改建議的鏈接都有了,因此我們可以找到每項特定修改的全部細節內容。

API 的變化

Swift 3 中最顯著的更新包括對標準庫采用一致的命名規則。 API Design Guidelines   包含核心開發團隊構建 Swift 3 時所確定的一些規則,可以為新手帶來很好的可讀性和易達性(accessibility)。核心開發團隊摒棄了“好的API設計總是要考慮調用現場(call site)”這一要領,努力在用法上清晰明了。閑話少說,下面來看看最有可能對我們產生影響的變化吧。

第一個參數的標簽

我們一起每天使用Swift語言,開始進行強制的轉換練習。

函數和方法的第一個參數總會用一個標簽表示,除非你想故意去掉。在這之前,調用函數或方法的時候,第一個參數的標簽是被省略掉的[ 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”和“and”。這些都是為了提高可讀性。

如果調用方法時不需要介詞,也不需要第一個參數的標簽也具有很好的可讀性,我們就要使用下劃線明確地去掉第一個參數名:

override func tableView(_tableView: UITableView, numberOfRowsInSec-tion section: Int)->Int{...}
    override func didMoveToView(_view:SKView){...}

在許多編程語言中,方法可能會有一個共用的名稱,然后會提供不同的參數名。Swift 也不例外。由于 API 被更直接地形式遷移了過來,所以我們就會遇到更多方法名重載的情況。下面的例子就是 index() 函數的兩種不同形式:

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

總而言之,函數和方法的第一個參數名所做的變化,使得其命名更具一致性,更容易學習理解。

省略不必要的部分

蘋果早期的庫函數中,方法會包含一個表示其返回值的名稱。由于 Swift 語言編譯器具有類型檢查功能,因此這樣的函數表示方法就沒有太大必要了。Swift 核心開發團隊盡量去掉沒有意義的部分,而保留有必要存在的內容。因此很多冗余的部分被省略掉了。

將 Objective-C 的庫轉換到原生的 Swift 變得更便捷了[ SE-0005 ]:

// old way, Swift 2, fllowed by new way, Swift 3
let blue = UIColor.blueColor()
let blue = UIColor.blue()

let min = numbers.minElement()
let min = numbers.min()

attributedString.appendAttributedString(anotherString)
attrubutedString.append(anotherString)

names.insert("Jane", atIndex: 0)
names.insert("Jane", at:0)

UIDevice.currentDevice()
UIDevice.current()

入流的 GCD 和 Core Graphics

說到舊有 API 一貫的樣式,GCD 和 Core Graphics 都急迫需要做較大的調整。

Grand Central Dispatch(GCD)被用在許多線程級任務上,比如長時間的計算或與服務器之間的通信。通過線程之間的切換,我們可以避免用戶界面被卡住。Libdispatch 這個庫是用 C 語言編寫的,也一直使用 C 風格的 API。如今,原生 Swift 語言的 API 則被再次定義 [ SE-0088 ]:

//old way, Swift 2
let queue = dispatch_queue_create("com.test.myqueue", nil)
dispatch_async(queue){
    print("Hello World")
}

//new way, Swift 3
let queue = DispatchQueue(lable:"com.test.myqueue")
queue.async{
    print("Hello World")
}

同樣的,Core Graphics 也用 C 語言編寫,在這之前使用一種奇怪的函數調用方式。現在則使用了一種新的方式 [ SE-0044 ]:

// old way, Swift 2
let ctx = UIGraphicsGetCurrentContext()
let rectangle = CGRect(x: 0, y: 0, width: 512, height: 512)
CGContextSetFillColorWithColor(ctr, 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()
    }

枚舉值使用大寫字母

Swift 語言中,還有一種與之前編碼風格相反的情況,枚舉值使用了“小駱駝拼寫法”(lowerCamelCase)。這種做法使得這些枚舉值與其他屬性及屬性值看起來更加統一[ 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)現在只有在數據類型名和協議命名時使用。雖然這可能需要一些時間去適應,但蘋果公司的核心開發團隊對此所做的努力很合理。

返回值的方法和修改值的方法

標準庫的命名,在動詞和名詞的使用上也更加一致。根據產生的效果和發生的動作來選定方法名。單憑經驗判斷,如果名稱中是包含像“-ed”和“-ing”這樣的后綴,我們就認為方法名是名詞,名詞性的方法會返回一個值。如果方法名沒有這樣的后綴,那么就很像是一個祈使句中的動詞。這些“動詞”方法在所占內存中執行動作。也就是修改了里面的內容。有好幾對方法都遵循這一名詞/動詞命名法的約定。例如[ SE-0006 ]:

customArray.enumerate()
customArray.enumerated()

customArray.reverse()
customArray.reversed()

customArray.sort() //changed from .sortInPlace()
customArray.sorted()

下面的這小段代碼就是例子:

var ages = [21, 10, 2] //variable, not constant, so you can modify it
ages.sort() //modified in place, value now [2, 10, 21]

for (index, age) in ages.enumerated() { // "-ed" noun returns a copy
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) -> {…} //new way, Swift 3

現在,參數列表被括號括起來了,然后才是返回值類型。這樣一切變得更清晰。同時函數類型更容易被識別出來。下面則是更突出的比較:

//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中新增加的功能

Swift 3 中最大的改變不光是對現有 API 所作的修改,還有很多 Swift 社區所做的努力,其中也包括 Swift API 中新增加的一些實用的功能。

訪問所屬的類型

當定義一個靜態屬性或方法的時候,我們隨時可以直接通過其類型對其進行調用:

CustomStruct.staticMethod()

如果我們編寫的是類型內部的代碼,仍然需要使用類型名稱來調用靜態方法。更簡單地說,我們可以調用Self得到當前實例所屬類型。首字母大寫的Self表示實例的類型,而首字母小寫的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

注意:   這一特性會被添加在Swift 3中,但是目前在Xcode 8 beta5版本中還不能使用。

函數 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
}

注意:   這一特性會被添加在Swift 3中,但是目前在Xcode 8 beta5版本中還不能使用。

零碎的變化

  • #keyPath() 和 #selector() 一樣,幫助我們在使用API的時候克服拼寫錯誤。
  • 我們可以在類型上調用pi,比如 Float.pi 、 CGFloat.pi 。大多數情況下編譯器都可以推斷出類型: let circumference = 2 * .pi *radius [ SE-0067 ]:
  • 在基礎類中,移除掉了前綴NS。我們現在可以使用 Calendar 和 Date 來代替 NSCalendar 和 NSDate 了。

編程工具的改進

Swift 是一門編程語言。這樣一來,編程很大程度上就會涉及所使用的開發環境——對于蘋果開發人員來說,就是 Xcode!編程工具的改進影響著我們每天的編程方式。

Swift 3 修復了編譯器和 IDE 中存在的 Bug,使錯誤和警告信息的精確度更高。正如我們所期望的,每一次發布,Swift 的編譯和運行過程都會變得更快:

  • 由于改進了字符串的哈希算法,存入字典的字符串效率提升為原來的三倍;
  • 由于將對象從堆區移入棧區,效率也提升為原來的 24 倍(某些情況下);
  • 編譯器可以一次緩存多個文件(文件整體被優化的情況下);
  • 優化了代碼的體量,編譯后的 Swift 代碼體量更小。蘋果的   Demobots   將編譯后的代碼體量減少至原來的 77%。

Xcode 也在逐漸去支持原生的 Swift:

  • 當我們對準像 sort() 這樣的 API 右鍵單擊后跳轉到其定義的時候,會跳到一個匿名的頭文件。現在,在 Xcode 8 中,我們會看到 sort() 方法其實是 Array 類的擴展。
  • Swift Snapshots   就像今天晚上發布的 Swift Evolution 所描述的那樣。在被完全合并到 Xcode 之前,Swift Snapshots 提供了使用新語法的機會。Xcode 8 可以在 playground 中加載和運行 Swift Snapshots。

Swift 包管理器(Swift Package Manager)

開源的 Swift 語言實際上包含了語言本身,核心類庫以及包管理器。這些所有內容組成了我們所認識的 Swift。Swift 包管理器( Swift Package Manager )定義了一個簡單的目錄結構,包括我們所共享和導入到項目中的所有 Swift 代碼。

你可能使用過 Cocoapods 或者 Carthage,Swift 包管理器與之類似。包管理器會下載依賴項并編譯它們,把這些依賴項鏈接(link)起來,創建類庫和可執行文件。已經有 1000 個類庫支持包管理器,在未來的幾個月,我們會看到更多支持包管理器的類庫。

未來計劃內的特性

前面提到過,Swift 3 通過努力避免突發的變化,讓我們的代碼在不同版本之間保持兼容。如果這種說法成立的話,那么就會有更高階的目標在這個版本中沒有實現,即泛型增強和程序二進制接口(ABI)的穩定性問題。

泛型增強包括協議約束的遞歸,這能夠使一個受約束的擴展符合新的協議(也就是說某個存放 Equatable 對象的數組也要遵守 Equatable 協議)。在這些特性完成之前,還不能說Swift是二進制接口穩定的。

程序二進制接口的穩定會使被編譯的程序和類庫在 Swift 不同版本之間能夠相互被編譯連接,相互也能進行交互。這對于不提供源代碼的第三方類庫由依賴項到庫的這一過程至關重要。因為新版本的 Swift 不僅需要這些第三方庫修改代碼,而且還需要對它們重新進行編譯 。

另外,由于目前我們無論創建 iOS 還是 macOS App 都要使用 Xcode,程序二進制接口的穩定性免去了 Swift 標準庫與二進制文件之間的捆綁。現在二進制文件額外包含有 2M 的文件大小,用來確保 App 能夠在以后的操作系統上運行。

總之,我們現在能夠保持源代碼版本間的兼容,但無法保證編譯后的二進制文件也具有兼容性。

Swift 將去何處?

由于開發者社區的改進工作精益求精,使得 Swift 不斷向前演變。雖然該語言仍處于起步階段,卻有著不錯的勢頭和前景。Swift 已經可以在 Linux 系統上運行了。在未來幾年內,我們很可能還會看到它在服務端運行。全新地設計一門編程語言肯定會有其優越性,因為一旦穩定下來,就很難再有機會破壞程序二進制接口的穩定性了。這是唯一可以不留遺憾地給語言糾錯的機會。

Swift 語言也在擴展其應用范圍。蘋果公司正在身體力行。該公司的開發團隊在 Music App、Console、Sierra 的畫中畫功能,以及 Xcode 的文檔查看器和 iPad 新版的 Swift Playground 中都使用了 Swift 語言。

說了這么多,讓人感到是在迫使非專業程序員也要來學習 Swift 語言。而從在 iPad 上支持 Swift,到一系列的教學方面的倡議都表明了這一點。

關鍵是 Swift 在持續改進:命名變得更加規范,代碼讀起來也更加清晰,遷移代碼也有了可用的工具。如果我們打算進步一深入了解的話,可以觀看 WWDC 的大會視頻 記錄。

可以肯定的是,2016 年年底 Swift 3 最終的發布會更加令人期待。我們也會繼續在此關注所有的新內容。所以,請繼續關注我們的圖書發布通告,相關視頻和教程。這些令人感到興奮的變化都會在這些內容中有相應的實踐。

你對 Swift 3 的哪些特性最感興趣?又希望我們最先講解哪些內容呢?快給我們留言吧!

 

來自:http://www.lupaworld.com/article-259864-1.html

 

 本文由用戶 624313247 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!