Swift語(yǔ)言從WWDC2014發(fā)布開始,到現(xiàn)在已經(jīng)發(fā)展了一年多時(shí)間,越來越多的開發(fā)者也開始學(xué)習(xí)和使用這門語(yǔ)言。但就我所了解的情況來看,在實(shí)際項(xiàng)目中Swift的應(yīng)用還是比較少。開發(fā)者給它的評(píng)價(jià)也是褒貶不一,有的說它的安全性高,有的說它的特性多,有的說它的學(xué)習(xí)成本高,還有的說它是一個(gè)玩具語(yǔ)言不適合工程。其實(shí)這都很正常,因?yàn)橐磺€(gè)人眼中有一千個(gè)哈姆雷特,語(yǔ)言的喜好本身就是一件很主觀的事情。具體這個(gè)語(yǔ)言怎么樣,適不適合工程,需要每個(gè)人實(shí)踐之后才能得出自己結(jié)論。
支持Unicode
代碼原生支持Unicode字符。不僅在字符串中,甚至變量名、函數(shù)名等都能直接使用Unicode字符。雖然看上去很強(qiáng)大,但似乎并沒有什么用,應(yīng)該沒人喜歡在編程時(shí)不停的切換輸入法吧?
采用嚴(yán)格的類型,并去掉了隱式類型轉(zhuǎn)換:
隱式類型轉(zhuǎn)換一直是一把雙刃劍,雖然使用便利,但是可能引入一些很難調(diào)試的BUG,不容忽視。把隱式類型轉(zhuǎn)換摘除,利大于弊。
從類型層面將空值nil隔離,使用時(shí)要求對(duì)空值進(jìn)行處理:
嚴(yán)格的語(yǔ)義邏輯
Swift對(duì)C語(yǔ)系一些常見的語(yǔ)義邏輯漏洞進(jìn)行了修改,比如if等條件限定為Bool類型,賦值“=”操作不再有返回值等(其實(shí)有,是Void,即空元組“()”)。雖然使用上沒有之前那么方便和靈活,但這種改變能杜絕很大一部分的手誤BUG,比如“==”寫成“=”,還能避免一些偷懶所引入的很隱秘的坑,對(duì)程序的穩(wěn)定性和程序員好習(xí)慣的培養(yǎng)有很大幫助。
易用性
沿用并完善了Objective-C的函數(shù)中綴調(diào)用方式,參數(shù)有了真正的名字,調(diào)用時(shí)帶上參數(shù)名能讓函數(shù)接口更容易理解,可讀性更好:
優(yōu)化了可變參數(shù)定義和使用方式:
在C語(yǔ)系中定義可變參數(shù)還需要va_list、va_start等,一段時(shí)間不用根本想不起來怎么寫,還得上網(wǎng)查,而在Swift中只需要遍歷一個(gè)數(shù)組就能取到所有參數(shù),非常方便。
優(yōu)化了控制流的使用:
Switch的case可以連寫,而且加入了很多實(shí)用的匹配模式,比如匹配范圍、元組、條件等,還可以自定義匹配模式,十分強(qiáng)大。另外分支默認(rèn)是break方式,不像在C語(yǔ)言中,明知道90%的case都是要break的,還要強(qiáng)制寫上。還有一個(gè)很好的優(yōu)化就是加入了跳轉(zhuǎn)標(biāo)簽,在多重循環(huán)間控制轉(zhuǎn)移的時(shí)候更靈活了。
加入了很多實(shí)用語(yǔ)法糖,僅僅一個(gè)閉包就有這么多簡(jiǎn)寫方式:
這些語(yǔ)法糖能節(jié)省大量的開發(fā)時(shí)間和代碼量,使用得當(dāng)也能讓代碼更清晰,可讀性更好。當(dāng)然如果濫用的話可能起反作用。
豐富的語(yǔ)言特性
Swift支持類、協(xié)議、繼承、多態(tài)等面向?qū)ο蟮恼Z(yǔ)言特性:
也有高級(jí)函數(shù)、閉包等函數(shù)式編程特性:
還有泛類型、泛函數(shù)、泛協(xié)議等泛型編程特性以及操作符自定義等新特性:
總之Swift加入了大量的流行語(yǔ)言特性,功能靈活、強(qiáng)大,但是語(yǔ)法點(diǎn)也增加了很多,導(dǎo)致語(yǔ)法學(xué)習(xí)難度增大,各位可以按需要進(jìn)行有針對(duì)性的學(xué)習(xí)。
值與引用
值與引用類型在某些情況下與我們的編程習(xí)慣可能會(huì)有些沖突,是Swift初學(xué)常遇到的一個(gè)坑。先看一個(gè)例子,定義兩個(gè)數(shù)組arr1和arr2,arr2用arr1賦值:
修改arr2[0]后,發(fā)現(xiàn)arr1[0]并沒有修改。由此可知在Swift中,Array類型是值類型。再來看看Array的實(shí)現(xiàn)方式。按住Command鍵點(diǎn)擊Array類型,進(jìn)入到Swift庫(kù),可以看到如下定義:
Array和Dictionary,包括Int、Set、Double等基本內(nèi)建數(shù)據(jù)類型都是由struct及其實(shí)現(xiàn)的一組協(xié)議構(gòu)成。由于struct類型是值類型,所以Swift中的基本內(nèi)建類型都是值類型。由于是值類型,所以每次賦值或者傳參的時(shí)候都會(huì)有個(gè)拷貝的過程。我們先來做個(gè)實(shí)驗(yàn):
運(yùn)行以上代碼可以發(fā)現(xiàn),在修改了arr[0]的情況下,賦值的時(shí)間是1783ms(模擬器下),而僅是讀取的情況,賦值時(shí)間是0ms。這個(gè)結(jié)果說明值傳遞使用了寫時(shí)拷貝(copy on write)技術(shù),也就是說只要不修改存儲(chǔ)的數(shù)據(jù),副本和原值共享內(nèi)存區(qū)域。因此我們?cè)谑褂眠@些值類型的時(shí)候一般有一些原則:
Optional
Optional可選類型是Swift的一個(gè)重要概念,也是初學(xué)者比較難理解的地方。我們經(jīng)常能在閱讀代碼時(shí)看到下面這樣的代碼:
有問號(hào)有感嘆號(hào),放的位置不一樣作用也不一樣,用的時(shí)候搞不清什么時(shí)候該用哪個(gè),只好跟著xcode提示走,掉進(jìn)坑里也不知道。要搞清楚這個(gè)問題先要明白Optional是什么。在Swift庫(kù)中可以找到Optional的定義:
Optional其實(shí)是個(gè)泛型枚舉,定義時(shí)的類型比如 Int? 等價(jià)于 Optional<Int>。它實(shí)現(xiàn)了NilLiteralConvertible協(xié)議,所以能被nil字面量賦值。當(dāng)可選類型用nil賦值時(shí),nil被轉(zhuǎn)化成None,當(dāng)用非nil賦值時(shí),轉(zhuǎn)化為Some(T)。Some(T)這種形式叫做相關(guān)值(Associated Values),可以這么理解,這是一種名叫Some,能存放T類型的盒子,我給它賦的值就放在這個(gè)盒子里保存。
可選類型相當(dāng)于對(duì)nil或?qū)嶋H的值做了封裝,所以使用Optional時(shí)需要將實(shí)際的值從Some(T)中取出,這個(gè)過程就叫解可選(unwrap)。
先來看看問號(hào)定義的可選類型:
問號(hào)定義的可選類型就是普通的Optional,常用的解可選方式有三種,如上圖所示。
再來看看感嘆號(hào)定義的可選類型:
感嘆號(hào)定義的可選類型叫做隱式解可選類型。在概念上與問號(hào)定義的可選類型并沒有什么區(qū)別,只是在使用形式上有些不同。
隱式解可選類型在用作右值時(shí)并不需要人為進(jìn)行解可選,它默認(rèn)由編譯器進(jìn)行強(qiáng)制解可選,相當(dāng)于編譯器自動(dòng)在后面添加一個(gè)感嘆號(hào)。這樣在使用的時(shí)候就不用強(qiáng)制對(duì)空值進(jìn)行處理,更方便一點(diǎn),但是卻十分危險(xiǎn),因?yàn)楸仨氂扇斯けWCopt_f在用到的地方必須不為nil,否則程序會(huì)crash。而人腦總不如機(jī)器保險(xiǎn),因此一般情況不建議使用隱式可選類型。
問號(hào)還有一種使用場(chǎng)景叫做可選鏈。先來看看這么一種情況:
我定義了一個(gè)Person類,類有father屬性表示他的父親,而孤兒可能不知道父親是誰,因此father是個(gè)可選類型?,F(xiàn)在來了一個(gè)需求,需要獲取某個(gè)人曾祖父的名字,我們可能會(huì)寫出如下代碼:
看上去很不美觀,寫起來更費(fèi)勁。針對(duì)這種情景,Swift做了優(yōu)化,加入了可選鏈這種語(yǔ)法糖,上面的代碼就能改寫為:
用問號(hào)把方法調(diào)用或?qū)傩垣@取等連接起來,組成一條調(diào)用鏈。意思就是我不關(guān)心中間過程,只關(guān)心最后結(jié)果,如果中途任何環(huán)節(jié)返回了nil,就直接返回nil,否則返回最后結(jié)果。這樣就能節(jié)省很多工作量,讓代碼看上去更美觀,結(jié)構(gòu)更清晰。需要注意的一點(diǎn)是,雖然name是確定的String類型,但是由于可選鏈上任一環(huán)節(jié)都可能返回nil,最后得到的是一個(gè)String?可選類型,所以還需要做一次解可選操作。
與Cocoa交互
要用Swift寫App首先需要了解的就是UI怎么寫、系統(tǒng)功能怎么調(diào)用。由于Swift并沒有重寫系統(tǒng)功能庫(kù),只是對(duì)Cocoa進(jìn)行了橋接,所以要調(diào)用系統(tǒng)功能就要與Cocoa的交互。Swift與Cocoa交互的細(xì)節(jié)非常多,但是并沒有太大難度,因?yàn)镃ocoa的使用與用Objective-C開發(fā)時(shí)沒有太大不同,一般來說跟著Xcode的提示走基本都沒有問題。需要注意的幾點(diǎn):
多線程
Swift語(yǔ)言本身并沒有多線程支持,因此要使用多線程還是要調(diào)用NSThread、GCD等:
此外,Object-C中一個(gè)很方便的代碼互斥方式@synchronized在swift中不支持,因此要實(shí)現(xiàn)代碼互斥需要自己使用鎖。當(dāng)然也可以模仿@synchronized自定義一個(gè)synchronized方法,利用尾部閉包造出原來的感覺:
單例
單例模式是移動(dòng)開發(fā)中常見的一種模式,其一般要求是:
在Object-C中單例通常是用dispatch_once來實(shí)現(xiàn)的,在Swift中同樣可以這么做。但是由于Swift中支持全局變量、常量的lazy初始化,我們可以簡(jiǎn)化單例的實(shí)現(xiàn):
通過let定義單例實(shí)例常量來保證線程安全,通過全局常量的lazy初始化來保證單例只初始化一次。
ARC
Swift中的ARC原理與Object-C中一樣,只不過在使用形式上有所不同。Swift中所有引用默認(rèn)都是強(qiáng)引用,另外加入了兩個(gè)ARC標(biāo)記:
由于weak引用在使用過程中可能變?yōu)閚il,所以weak引用必須是可選類型(Optional)。另外Swift對(duì)閉包捕獲的變量的標(biāo)記做了優(yōu)化:
在Object-C中這種情況需要在閉包之外定義一個(gè)weak self,然后閉包捕獲weak self。Swift中只需要把weak self寫在閉包參數(shù)表之前的中括號(hào)中即可完成同樣功能,這種方式代碼結(jié)構(gòu)更清晰,可讀性更好。需要注意的是在閉包內(nèi)self是weak的,是個(gè)可選類型,因此使用self時(shí)需要解可選。
Delegate
代理模式是開發(fā)中很常見的一種模式,它的實(shí)現(xiàn)原理與Object-C類似,也是通過協(xié)議來確定代理接口,用實(shí)現(xiàn)協(xié)議的實(shí)例來充當(dāng)代理:
不同的地方在于,Object-C中delegate是id類型的,而swift中協(xié)議是一種基本類型,delegate可以直接定義為協(xié)議類型,這樣能讓代理的職責(zé)更明確。要注意的地方是delegate是weak的,所以必須使用可選類型,而且weak標(biāo)記的必須是引用,所以protocol必須打上class標(biāo)記,表示該協(xié)議只能被class實(shí)現(xiàn),這樣協(xié)議類型才能當(dāng)做引用類型使用。
自定義操作符
Swift中可以自定義操作符,自定義一個(gè)操作符需要兩個(gè)要素:
比如我們可以定義一個(gè)笑臉操作符,他在字符串后面添加一個(gè)笑臉(^_^):
函數(shù)式編程
在Swift中,函數(shù)是first-class,也就是說函數(shù)可以作為參數(shù)傳入也可以作為返回值返回,也可以給變量賦值。函數(shù)式編程是一種很強(qiáng)大、很靈活的思想,在Object-C中也有block等函數(shù)式編程思想,但并不明顯,在Swift中這一點(diǎn)得到了強(qiáng)化。
比如說可以實(shí)現(xiàn)一個(gè)函數(shù)工廠:
泛型編程
Swift中增加了泛型這個(gè)概念,泛型是一種很好的代碼復(fù)用機(jī)制,用于將類型不同但實(shí)現(xiàn)相同的代碼統(tǒng)一起來。泛型在Swift中應(yīng)用非常廣泛,你只要跳轉(zhuǎn)到Swift的庫(kù)文件就會(huì)發(fā)現(xiàn)類型、操作符、全局函數(shù)的定義中大量應(yīng)用了泛型,因此不再做詳細(xì)介紹。這里有一個(gè)小例子,利用操作符自定義、函數(shù)式和泛型在代碼中實(shí)現(xiàn)管道機(jī)制:
Swift有著更嚴(yán)格的類型和更規(guī)范的語(yǔ)義,針對(duì)容易造成BUG的點(diǎn)進(jìn)行了優(yōu)化,又加入了很多不錯(cuò)的語(yǔ)法糖,代碼更簡(jiǎn)潔、更安全。它吸收了大量其他語(yǔ)言的優(yōu)秀特性,可以實(shí)現(xiàn)一些強(qiáng)大靈活的設(shè)計(jì)模式,但也造成了其語(yǔ)法繁雜的缺點(diǎn),增加了學(xué)習(xí)的難度。Swift本身的設(shè)計(jì)目標(biāo)是高效、靈巧,但由于需要兼容Cocoa,導(dǎo)致其設(shè)計(jì)受到牽制,引入了一些有隱患的設(shè)計(jì)。由于這些特點(diǎn),編寫Swift代碼其實(shí)很依賴IDE的輔助,但目前為止xcode的表現(xiàn)還不穩(wěn)定,經(jīng)常提示錯(cuò)誤,再加上幾乎每次xcode更新都伴隨著Swift語(yǔ)法修改,Swift想要廣泛應(yīng)用于實(shí)際工程還有一段路要走,而Swift2.0的發(fā)布和Swift開源化,無疑將加快這個(gè)進(jìn)程。