隨着剛剛結束的 WWDC 2015 蘋果發佈了一系列更新,這其中就包括了使人振奮的 Swift 2.0
。 這是對以前語言特性的一次大幅的更新,加入了不少實用和方便的元素,下面咱們就一塊兒來看看此次更新都包括了什麼。swift
如今咱們在代碼中輸入 println("xxx")
這樣的調用時,編譯器就會報錯:數組
都已經變成通用的 print
方式了:安全
print("xxx")
好比在 Swift 1.2
中,咱們要判斷某元素是否在數組中,咱們會用到 contains
函數:網絡
var apps = ["Youtube","Google","Facebook"] if contains(apps, "Google") { println("ok") }
而在 Swift 2.0
中,變成了直接調用數組對象 apps
的 contains
方法進行這個操做,這種調用方式更加的結構化,和麪向對象化:app
if apps.contains("Google") { print("ok") }
對於字符串操做,也是同樣,若是在 Swift 1.2
中,咱們要得到字符串的長度,咱們會這樣:函數
let str = "Swift App" let c = count(str)
而在 Swift 2.0
中,咱們只需調用 str
對象的 count
方法,便可完成字符串數量的統計:優化
let str = "Swift App" let c = str.characters.count
do-while
循環語句在 Swift 2.0
中也發生了變化。以往,咱們代碼中用到 do-while
循環,會這樣處理:ui
var counter = 5 do { print(counter) counter-- } while counter > 0
而在 swift 2.0
中, do-while
循環中的 do
關鍵字被替換成了 repeat
,若是咱們在 Swift 2.0
還使用 do
關鍵字的話,就會致使編譯錯誤:url
Swift 2.0
中咱們使用 repeat-while
循環:spa
repeat {
print(counter) counter-- } while counter > 0
在 Swift 2.0
中,之因此將 do-while
循環變成了 repeat-while
循環,是由於 do
關鍵字另有他用,這個在後面咱們會講到。
在以往的開發經歷中,最讓咱們頭疼的一個問題就是 API
的版本兼容。好比咱們用了一個 iOS 8
引入的方法,但咱們的 App
運行在了 iOS 7
的設備上,若是這時不手動進行系統版本檢測的話, 咱們的 App
就會直接的崩潰掉。而對於這種 API
編譯器不會給咱們任何的提示,只能靠着人工去逐個處理,不只麻煩,並且很容易形成遺漏,致使嚴重的崩潰問題。
Swift 2.0
新引入的 #available
機制,就解決了這一問題。 新的 Swift
編譯器,會在編譯的時候就進行檢測,舉個例子,好比 UIAlertController
這個類是 iOS 8.0
引入,但咱們的項目設置的 Deployment Target
是 iOS 7.0
, 這時候咱們在編譯代碼的時候,編譯器就會給出咱們這樣的警告:
看到了吧,在 Swift 2.0
中,編譯器會自動幫咱們檢測哪些 API
須要進行版本兼容判斷,很是的強大吧。這樣就減去了咱們不少麻煩,而且大大減小了 App
出錯的機率。
編譯器幫咱們檢測到問題以後,接下來咱們就要處理這個問題,也就是進行系統版本的條件判斷,也就是經過 #available
來判斷:
if #available(iOS 8.0, *) { let alert = UIAlertController(title: "test", message: "app", preferredStyle: .Alert) UIApplication.sharedApplication().keyWindow?.rootViewController?.presentViewController(alert, animated: true, completion: nil) } else { let alert = UIAlertView(title: "test", message: "app", delegate: nil, cancelButtonTitle: "ok") alert.show() }
咱們看上面的代碼 if #available(iOS 8.0, *)
用於檢測當前的系統版本是否在 iOS 8
或以上。若是是的話,那麼咱們就使用 UIAlertController
。 不然,咱們還繼續使用 UIAlertView
。
如今編譯咱們的代碼,便可編譯經過。 #available
這個特性的提供,算是對咱們現有的開發方式的一個改進。也體現了 Swift
的安全性爲本的核心理念。
感受腦洞小開哦~
Swift 2.0
中提供了對錯誤處理更好的支持,增長了 try-catch
語句。如今咱們能夠這樣進行異常處理操做了:
do { let content = try NSString(contentsOfFile: "/file/path/str.txt", encoding: NSUTF8StringEncoding) } catch { print("read content fail") }
是否是發現了 do
關鍵字了呢,Swift 2.0
中將 do
關鍵字用到了異常處理塊中。還有一點和其餘語言不一樣的是,這裏的 try
關鍵字是寫在具體調用代碼行上面的。也就是說,那個語句會有可能拋出異常,咱們纔在哪一個語句前面加上 try
關鍵字。這種方式有一個好處。就是咱們能夠一目瞭然的看到那些代碼會拋出異常。而不是將全部代碼都混在 try-catch 語句塊中。
咱們還能夠對咱們本身定義的函數聲明異常拋出,使用 throws
關鍵字:
func requestImage(urlString:String) throws -> UIImage? { if let url = NSURL(string: urlString) { if let data = NSData(contentsOfURL: url) { return UIImage(data: data) } } return nil }
在返回值類型聲明前面加上 throws
關鍵字,便可將咱們的函數聲明爲拋出異常類型:
func requestImage(urlString:String) throws -> UIImage?
接下來咱們還須要定義咱們要拋出的異常類型。咱們能夠經過 ErrorType
類型的枚舉聲明來定義咱們本身的異常類型:
enum RequestImageError : ErrorType { case NetworkError case URLError }
咱們定義了兩個異常類型,NetworkError
表示網絡錯誤,URLError
表示 url 錯誤。 咱們還須要在咱們的方法中拋出這些異常:
func requestImage(urlString:String) throws -> UIImage? { if let url = NSURL(string: urlString) { if let data = NSData(contentsOfURL: url) { return UIImage(data: data) } else { throw RequestImageError.NetworkError } } else { throw RequestImageError.URLError } }
如今調用這個方法的時候,就能夠經過 try,catch 來處理異常狀況了:
do { try requestImage("http://swiftcafe.io/images/qrcode.jpg") } catch RequestImageError.NetworkError { print("network error") } catch RequestImageError.URLError { print("url error") }
Swift 2.0
中新引入了一個叫作 guard
的關鍵字用於條件判斷處理。舉個例子來講,咱們之前在代碼中對函數的參數進行驗證的時候,可能會用到這種方法:
func printName(firstName:String?, _ lastName:String?) { if firstName != nil { if lastName != nil { print("\(lastName!) \(firstName!)") } } }
咱們對每個參數都用一個 if
語句來判斷,這樣的代碼結構讀起來結構不是很清晰,而且若是參數的數量比較多的話,if
語句的嵌套層數就會很深,致使可讀性的下降。那麼爲了減小嵌套層數,咱們還能夠這樣:
func printNameByIf(firstName:String?, _ lastName:String?) { if firstName == nil { return } if lastName == nil { return } print("\(lastName!) \(firstName!)") }
咱們在函數的開始,用 if 語句來判斷各個參數。當這些判斷失敗的時候,會直接 return
。只有當全部的判斷都經過,纔會執行函數中真正的代碼。這樣作,解決了以前 if
嵌套的可讀性的問題,好了不少。
但這樣依然有它的問題。好比,這樣的可讀性依然不是很好,不能充分顯示這個 if
語句的意圖。而且,對於 Optional 類型的值,也沒有進行很好的處理。
基於這些狀況,Swift 2.0
中引入了 guard
關鍵字,我看來看一下如何用 guard
來實現這個方法:
func printNameByGuard(firstName:String?, _ lastName:String?) { guard let first = firstName else { return } guard let last = lastName else { return } print("\(first) \(last)") }
咱們這裏用到了 guard
關鍵字,來進行參數條件的判斷。比起以前的 if
判斷,代碼的可讀性更強,而且意圖更加明確。 guard
還有一個好處就是對於 Optional的解包的做用域是在函數內徹底可見的。 好比上例中,咱們解包出的 first
和 last
,能夠在 guard
執行完後,繼續使用。
gurad
關鍵字,除了用在參數判斷返回的場景下,還能用在不少別的地方:
guard app.characters.count > 0 else { throw InputError.NameIsEmpty } guard #available(iOS 8, *) else { return }
在瞭解 defer
關鍵字以前,讓咱們先了解一個比較常見的例子:
func getFileContent(path:String) -> NSString { guard path.characters.count > 0 else { showGetFinished() return "" } if NSFileManager.defaultManager().fileExistsAtPath(path) { do { let content = try NSString(contentsOfFile: path, encoding: NSUTF8StringEncoding) showGetFinished() return content } catch { showGetFinished() return "" } } else { showGetFinished() return "" } }
上面的函數就是一個簡單的讀取文件內容的方法,咱們注意看一下里面的 showGetFinished()
方法,在多個分支都被調用了。實際上它的邏輯只是幹一件事,就是在函數結束的時候顯示一下讀取完成消息。顯然咱們這裏的代碼在每一個 if
調用 return
返回以前,都調用了 showGetFinished()
方法。在語法上,這樣的調用是沒問題的。但從業務邏輯角度考慮,其實這樣作是比較笨拙的。但咱們又受制於語法限制,只能寫出不少這樣形態的代碼。
這就是 Swift 2.0
中引入 defer
關鍵字的做用了。咱們來看看 Swift 2.0
中是怎麼處理這個問題的:
func getFileContentDefer(path:String) -> NSString { defer { showGetFinished() } guard path.characters.count > 0 else { return "" } if NSFileManager.defaultManager().fileExistsAtPath(path) { do { let content = try NSString(contentsOfFile: path, encoding: NSUTF8StringEncoding) return content } catch { return "" } } else { return "" } }
咱們看一下上面的代碼,全部分支中的 showGetFinished()
調用都不見了,咱們只在函數的第一行看到一句 defer { showGetFinished() }
。 若是咱們執行這個函數,就會發現不管代碼走到哪一個分支,defer
語句塊中的 showGetFinished()
都會被調用。
defer
語句就至關於在它的做用域中執行一個收尾工做,又叫作稍後執行,好比咱們例子中的函數,showGetFinished()
方法就符合這個邏輯,在函數執行完成後,作一些收尾的操做(好比這個例子裏面要顯示一下狀態信息)。
defer
從程序語法結構上,作了一個改進,以往咱們爲了達到相似的目的須要不斷的經過 if-else
分支來實現的邏輯,能夠可以更加清晰和簡潔的表達出來。
恩,不錯不錯。喜笑顏開~
defer
語句塊不只可以在函數中使用,它幾乎能夠在任何 {..}
語句塊中使用:
func branch() -> String { var str = "" str += "1" defer { str += "2" } let counter = 3; if counter > 0 { str += "3" defer { str += "4" } str += "5" } str += "6" return str }
咱們此次,在 branch
函數和它裏面的 if
語句塊中都用到了 defer
語句塊。咱們函數最終返回的 str 中的內容是:
13546
這個結果和各位想到的結果是否同樣呢?
Swift 2.0
是一個重大的改進,包括了不少的優化與改動,這裏面只介紹了其中一些比較顯著的優化與更新。更多的更新內容在後期還會爲你們繼續整理的哦。從此次更新中咱們不難看到 Swift
依然秉持着它基於類型安全已經更現代化的開發方式的理念。在如今產品都注重用戶體驗的同時,相信 Swift
也會給咱們這些開發者更好的開發體驗。