隨著剛剛結(jié)束的 WWDC 2015 蘋(píng)果發(fā)布了一系列更新忧陪,這其中就包括了令人振奮的 Swift 2.0
。 這是對(duì)之前語(yǔ)言特性的一次大幅的更新近范,加入了很多實(shí)用和方便的元素嘶摊,下面我們就一起來(lái)看看這次更新都包括了什么。
將 println 函數(shù)統(tǒng)一為 print
現(xiàn)在我們?cè)诖a中輸入 println("xxx")
這樣的調(diào)用時(shí)评矩,編譯器就會(huì)報(bào)錯(cuò):
都已經(jīng)變成通用的 print
方式了:
print("xxx")
語(yǔ)言的結(jié)構(gòu)性更強(qiáng)
比如在 Swift 1.2
中叶堆,我們要判斷某元素是否在數(shù)組中,我們會(huì)用到 contains
函數(shù):
var apps = ["Youtube","Google","Facebook"]
if contains(apps, "Google") {
println("ok")
}
而在 Swift 2.0
中斥杜,變成了直接調(diào)用數(shù)組對(duì)象 apps
的 contains
方法進(jìn)行這個(gè)操作虱颗,這種調(diào)用方式更加的結(jié)構(gòu)化俯萌,和面向?qū)ο蠡?/p>
if apps.contains("Google") {
print("ok")
}
對(duì)于字符串操作,也是一樣上枕,如果在 Swift 1.2
中咐熙,我們要獲得字符串的長(zhǎng)度,我們會(huì)這樣:
let str = "Swift App"
let c = count(str)
而在 Swift 2.0
中辨萍,我們只需調(diào)用 str
對(duì)象的 count
方法棋恼,即可完成字符串?dāng)?shù)量的統(tǒng)計(jì):
let str = "Swift App"
let c = str.characters.count
do-while 循環(huán)語(yǔ)法關(guān)鍵詞的改動(dòng)
do-while
循環(huán)語(yǔ)句在 Swift 2.0
中也發(fā)生了變化。以往锈玉,我們代碼中用到 do-while
循環(huán)爪飘,會(huì)這樣處理:
var counter = 5
do {
print(counter)
counter--
} while counter > 0
而在 swift 2.0
中, do-while
循環(huán)中的 do
關(guān)鍵字被替換成了 repeat
拉背,如果我們?cè)?Swift 2.0
還使用 do
關(guān)鍵字的話师崎,就會(huì)導(dǎo)致編譯錯(cuò)誤:
Swift 2.0
中我們使用 repeat-while
循環(huán):
repeat {
print(counter)
counter--
} while counter > 0
在 Swift 2.0
中,之所以將 do-while
循環(huán)變成了 repeat-while
循環(huán)椅棺,是因?yàn)?do
關(guān)鍵字另有他用犁罩,這個(gè)在后面我們會(huì)講到。
新增了 #available 標(biāo)注來(lái)進(jìn)行多版本兼容性支持
在以往的開(kāi)發(fā)經(jīng)歷中两疚,最讓我們頭疼的一個(gè)問(wèn)題就是 API
的版本兼容床估。比如我們用了一個(gè) iOS 8
引入的方法,但我們的 App
運(yùn)行在了 iOS 7
的設(shè)備上诱渤,如果這時(shí)不手動(dòng)進(jìn)行系統(tǒng)版本檢測(cè)的話丐巫, 我們的 App
就會(huì)直接的崩潰掉。而對(duì)于這種 API
編譯器不會(huì)給我們?nèi)魏蔚奶崾旧酌溃荒芸恐斯とブ饌€(gè)處理递胧,不僅麻煩,而且很容易造成遺漏赡茸,導(dǎo)致嚴(yán)重的崩潰問(wèn)題缎脾。
Swift 2.0
新引入的 #available
機(jī)制,就解決了這一問(wèn)題坛掠。 新的 Swift
編譯器赊锚,會(huì)在編譯的時(shí)候就進(jìn)行檢測(cè),舉個(gè)例子屉栓,比如 UIAlertController
這個(gè)類(lèi)是 iOS 8.0
引入舷蒲,但我們的項(xiàng)目設(shè)置的 Deployment Target
是 iOS 7.0
, 這時(shí)候我們?cè)诰幾g代碼的時(shí)候,編譯器就會(huì)給出我們這樣的警告:
看到了吧友多,在 Swift 2.0
中牲平,編譯器會(huì)自動(dòng)幫我們檢測(cè)哪些 API
需要進(jìn)行版本兼容判斷,非常的強(qiáng)大吧域滥。這樣就減去了我們很多麻煩纵柿,并且大大減少了 App
出錯(cuò)的概率蜈抓。
編譯器幫我們檢測(cè)到問(wèn)題之后,接下來(lái)我們就要處理這個(gè)問(wèn)題昂儒,也就是進(jìn)行系統(tǒng)版本的條件判斷沟使,也就是通過(guò) #available
來(lái)判斷:
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, *)
用于檢測(cè)當(dāng)前的系統(tǒng)版本是否在 iOS 8
或以上。如果是的話渊跋,那么我們就使用 UIAlertController
腊嗡。 否則,我們還繼續(xù)使用 UIAlertView
拾酝。
現(xiàn)在編譯我們的代碼燕少,即可編譯通過(guò)。 #available
這個(gè)特性的提供蒿囤,算是對(duì)我們現(xiàn)有的開(kāi)發(fā)方式的一個(gè)改進(jìn)客们。也體現(xiàn)了 Swift
的安全性為本的核心理念。
感覺(jué)腦洞小開(kāi)哦~
錯(cuò)誤處理 try,catch 語(yǔ)句的增加
Swift 2.0
中提供了對(duì)錯(cuò)誤處理更好的支持材诽,增加了 try-catch
語(yǔ)句〉状欤現(xiàn)在我們可以這樣進(jìn)行異常處理操作了:
do {
let content = try NSString(contentsOfFile: "/file/path/str.txt", encoding: NSUTF8StringEncoding)
} catch {
print("read content fail")
}
是不是發(fā)現(xiàn)了 do
關(guān)鍵字了呢,Swift 2.0
中將 do
關(guān)鍵字用到了異常處理塊中岳守。還有一點(diǎn)和其他語(yǔ)言不同的是凄敢,這里的 try
關(guān)鍵字是寫(xiě)在具體調(diào)用代碼行上面的碌冶。也就是說(shuō)湿痢,那個(gè)語(yǔ)句會(huì)有可能拋出異常,我們才在哪個(gè)語(yǔ)句前面加上 try
關(guān)鍵字扑庞。這種方式有一個(gè)好處譬重。就是我們可以一目了然的看到那些代碼會(huì)拋出異常。而不是將所有代碼都混在 try-catch 語(yǔ)句塊中罐氨。
throws 和 throw 關(guān)鍵字臀规,以及自定義異常類(lèi)型
我們還可以對(duì)我們自己定義的函數(shù)聲明異常拋出,使用 throws
關(guān)鍵字:
func requestImage(urlString:String) throws -> UIImage? {
if let url = NSURL(string: urlString) {
if let data = NSData(contentsOfURL: url) {
return UIImage(data: data)
}
}
return nil
}
在返回值類(lèi)型聲明前面加上 throws
關(guān)鍵字,即可將我們的函數(shù)聲明為拋出異常類(lèi)型:
func requestImage(urlString:String) throws -> UIImage?
接下來(lái)我們還需要定義我們要拋出的異常類(lèi)型栅隐。我們可以通過(guò) ErrorType
類(lèi)型的枚舉聲明來(lái)定義我們自己的異常類(lèi)型:
enum RequestImageError : ErrorType {
case NetworkError
case URLError
}
我們定義了兩個(gè)異常類(lèi)型塔嬉,NetworkError
表示網(wǎng)絡(luò)錯(cuò)誤,URLError
表示 url 錯(cuò)誤租悄。 我們還需要在我們的方法中拋出這些異常:
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
}
}
現(xiàn)在調(diào)用這個(gè)方法的時(shí)候谨究,就可以通過(guò) try,catch 來(lái)處理異常情況了:
do {
try requestImage("http://swiftcafe.io/images/qrcode.jpg")
} catch RequestImageError.NetworkError {
print("network error")
} catch RequestImageError.URLError {
print("url error")
}
guard 關(guān)鍵字
Swift 2.0
中新引入了一個(gè)叫做 guard
的關(guān)鍵字用于條件判斷處理。舉個(gè)例子來(lái)說(shuō)泣棋,我們以前在代碼中對(duì)函數(shù)的參數(shù)進(jìn)行驗(yàn)證的時(shí)候胶哲,可能會(huì)用到這種方法:
func printName(firstName:String?, _ lastName:String?) {
if firstName != nil {
if lastName != nil {
print("\\\\(lastName!) \\\\(firstName!)")
}
}
}
我們對(duì)每一個(gè)參數(shù)都用一個(gè) if
語(yǔ)句來(lái)判斷,這樣的代碼結(jié)構(gòu)讀起來(lái)結(jié)構(gòu)不是很清晰潭辈,并且如果參數(shù)的數(shù)量比較多的話鸯屿,if
語(yǔ)句的嵌套層數(shù)就會(huì)很深澈吨,導(dǎo)致可讀性的降低。那么為了減少嵌套層數(shù)寄摆,我們還可以這樣:
func printNameByIf(firstName:String?, _ lastName:String?) {
if firstName == nil {
return
}
if lastName == nil {
return
}
print("\\\\(lastName!) \\\\(firstName!)")
}
我們?cè)诤瘮?shù)的開(kāi)始谅辣,用 if 語(yǔ)句來(lái)判斷各個(gè)參數(shù)。當(dāng)這些判斷失敗的時(shí)候婶恼,會(huì)直接 return
屈藐。只有當(dāng)所有的判斷都通過(guò),才會(huì)執(zhí)行函數(shù)中真正的代碼熙尉。這樣做联逻,解決了之前 if
嵌套的可讀性的問(wèn)題,好了很多检痰。
但這樣依然有它的問(wèn)題包归。比如,這樣的可讀性依然不是很好铅歼,不能充分顯示這個(gè) if
語(yǔ)句的意圖公壤。并且,對(duì)于 Optional 類(lèi)型的值椎椰,也沒(méi)有進(jìn)行很好的處理厦幅。
基于這些情況,Swift 2.0
中引入了 guard
關(guān)鍵字慨飘,我看來(lái)看一下如何用 guard
來(lái)實(shí)現(xiàn)這個(gè)方法:
func printNameByGuard(firstName:String?, _ lastName:String?) {
guard let first = firstName else {
return
}
guard let last = lastName else {
return
}
print("\\\\(first) \\\\(last)")
}
我們這里用到了 guard
關(guān)鍵字确憨,來(lái)進(jìn)行參數(shù)條件的判斷。比起之前的 if
判斷瓤的,代碼的可讀性更強(qiáng)休弃,并且意圖更加明確。 guard
還有一個(gè)好處就是對(duì)于 Optional 的解包的作用域是在函數(shù)內(nèi)完全可見(jiàn)的圈膏。 比如上例中塔猾,我們解包出的 first
和 last
,可以在 guard
執(zhí)行完后稽坤,繼續(xù)使用丈甸。
gurad
關(guān)鍵字,除了用在參數(shù)判斷返回的場(chǎng)景下尿褪,還能用在很多別的地方:
guard app.characters.count > 0 else {
throw InputError.NameIsEmpty
}
guard #available(iOS 8, *) else {
return
}
defer 關(guān)鍵字
在了解 defer
關(guān)鍵字之前睦擂,讓我們先了解一個(gè)比較常見(jiàn)的例子:
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 ""
}
}
上面的函數(shù)就是一個(gè)簡(jiǎn)單的讀取文件內(nèi)容的方法,我們注意看一下里面的 showGetFinished()
方法茫多,在多個(gè)分支都被調(diào)用了祈匙。實(shí)際上它的邏輯只是干一件事,就是在函數(shù)結(jié)束的時(shí)候顯示一下讀取完成消息。顯然我們這里的代碼在每個(gè) if
調(diào)用 return
返回之前夺欲,都調(diào)用了 showGetFinished()
方法跪帝。在語(yǔ)法上,這樣的調(diào)用是沒(méi)問(wèn)題的些阅。但從業(yè)務(wù)邏輯角度考慮伞剑,其實(shí)這樣做是比較笨拙的。但我們又受制于語(yǔ)法限制市埋,只能寫(xiě)出很多這樣形態(tài)的代碼黎泣。
這就是 Swift 2.0
中引入 defer
關(guān)鍵字的作用了。我們來(lái)看看 Swift 2.0
中是怎么處理這個(gè)問(wèn)題的:
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()
調(diào)用都不見(jiàn)了抒倚,我們只在函數(shù)的第一行看到一句 defer { showGetFinished() }
。 如果我們執(zhí)行這個(gè)函數(shù)坷澡,就會(huì)發(fā)現(xiàn)無(wú)論代碼走到哪個(gè)分支托呕,defer
語(yǔ)句塊中的 showGetFinished()
都會(huì)被調(diào)用。
defer
語(yǔ)句就相當(dāng)于在它的作用域中執(zhí)行一個(gè)收尾工作频敛,又叫做稍后執(zhí)行项郊,比如我們例子中的函數(shù),showGetFinished()
方法就符合這個(gè)邏輯斟赚,在函數(shù)執(zhí)行完成后着降,做一些收尾的操作(比如這個(gè)例子里面要顯示一下?tīng)顟B(tài)信息)。
defer
從程序語(yǔ)法結(jié)構(gòu)上拗军,做了一個(gè)改進(jìn)任洞,以往我們?yōu)榱诉_(dá)到類(lèi)似的目的需要不斷的通過(guò) if-else
分支來(lái)實(shí)現(xiàn)的邏輯,可以能夠更加清晰和簡(jiǎn)潔的表達(dá)出來(lái)食绿。
恩侈咕,不錯(cuò)不錯(cuò)。喜笑顏開(kāi)~
defer
語(yǔ)句塊不僅能夠在函數(shù)中使用器紧,它幾乎可以在任何 {..}
語(yǔ)句塊中使用:
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
函數(shù)和它里面的 if
語(yǔ)句塊中都用到了 defer
語(yǔ)句塊楼眷。我們函數(shù)最終返回的 str 中的內(nèi)容是:
13546
這個(gè)結(jié)果和各位想到的結(jié)果是否一樣呢铲汪?
Swift 2.0
是一個(gè)重大的改進(jìn),包括了很多的優(yōu)化與改動(dòng)罐柳,這里面只介紹了其中一些比較顯著的優(yōu)化與更新掌腰。更多的更新內(nèi)容在后期還會(huì)為大家繼續(xù)整理的哦。從這次更新中我們不難看到 Swift
依然秉持著它基于類(lèi)型安全已經(jīng)更現(xiàn)代化的開(kāi)發(fā)方式的理念张吉。在現(xiàn)在產(chǎn)品都注重用戶(hù)體驗(yàn)的同時(shí)齿梁,相信 Swift
也會(huì)給我們這些開(kāi)發(fā)者更好的開(kāi)發(fā)體驗(yàn)。
更多精彩內(nèi)容可以關(guān)注微信公眾號(hào):
swift-cafe