最近看了兩本書(shū), 第一本是Objc.io出的Advanced Swift和王巍大大出的Swifter tips. 后者在作者的博客上有更新, 應(yīng)該已經(jīng)更新完了吧.
這里列出一些看過(guò)了筆記, 也是比較粗糙, 只是大概都過(guò)了一遍, 把一些之前遺漏或者有錯(cuò)漏的地方補(bǔ)全了.
一. Collection
1.值類(lèi)型的賦值雖然是copy, 但是實(shí)際上會(huì)是"copy on write”, 只有在真正發(fā)生寫(xiě)操作的時(shí)候才會(huì)進(jìn)行修改;
2.需要用for循環(huán)遍歷的時(shí)候考慮一下map函數(shù), 它可以使得代碼更加簡(jiǎn)潔, 同時(shí)可以讓原本不得不為var的變量變?yōu)閘et;3.為了避免不必要的copy, 數(shù)組的范圍下標(biāo)訪問(wèn)返回的集合是ArraySlice<T>類(lèi)型的, 它有與數(shù)組一樣的方法, 所以可以被當(dāng)做數(shù)組, 如果實(shí)在需要轉(zhuǎn)換就用Array(slice)來(lái)構(gòu)造一個(gè);
需要注意的是, 切面可以增加數(shù)組元素, 但是不能修改, 如下面的代碼:
var array = ["1","2","3"]
var slices = array[1..<array.endIndex]
slices[0] = “a” // crash
slices.append("4”) // OK
// 存疑:
array[1] = “22” // 執(zhí)行后slices并沒(méi)有響應(yīng)的變化, 所以, 對(duì)內(nèi)部實(shí)現(xiàn)還是有疑問(wèn)
4.Dictionary的updateValue方法可以返回舊值5.GeneratorType協(xié)議由于其只能被訪問(wèn)一次, 因此其實(shí)現(xiàn)者最好是class而不是struct6.對(duì)集合的訪問(wèn)盡量不要用subscript, 可以用for-in和map, filter等高階函數(shù)實(shí)現(xiàn), 幾個(gè)”特殊"的情況:1). 對(duì)下標(biāo)的遍歷: for idx in collection.indices2). 對(duì)下標(biāo)和元素的遍歷: for (idx, element) in collection.enumerate()7.嚴(yán)格說(shuō)來(lái)[1,2,3]這樣的值, 它的類(lèi)型不是Array, 而是ArrayLiteral, 只是因?yàn)锳rray實(shí)現(xiàn)了ArrayLiteralConvertible協(xié)議, 所以才能通過(guò)這樣的字面值來(lái)構(gòu)造Array, 同樣的還有DictionaryLiteralConvertible, IntegerLiteralConvertible,StringLiteralConvertible等等8.collection的starIndex不一定從0開(kāi)始的, 所以寫(xiě)C風(fēng)格循環(huán)的時(shí)候不要var i = 0, 而應(yīng)該是var i = collection.startIndex
9.case的模式匹配:
for case let variable? in mayNilCollection{
}
等同于:
for let variable in mayNilCollection where variable != nil {
}
同時(shí)
for case nil in mayNilCollection {
}
可以幫你找出集合中有多少個(gè)nil
同時(shí)case還可以和if一起用:
let j = 5
if case 0..<10 = j {
}
- lazy修飾符:
lazy可以對(duì)屬性進(jìn)行修飾, 類(lèi)似于ObjC里面的手動(dòng)控制一樣. 同時(shí)Swift里面的標(biāo)準(zhǔn)庫(kù)也提供了一套lazy方法, 用起來(lái)是這樣的:
let data = 1...3
let result = data.lazy.map { (i: Int) -> Int in
print("正在處理 \(i)")
return i * 2
}
print("準(zhǔn)備訪問(wèn)結(jié)果")
for i in result {
print("操作后結(jié)果為 \(i)")
}
print("操作完畢")
//輸出結(jié)果為:
// 準(zhǔn)備訪問(wèn)結(jié)果
// 正在處理 1
// 操作后結(jié)果為 2
// 正在處理 2
// 操作后結(jié)果為 4
// 正在處理 3
// 操作后結(jié)果為 6
// 操作完畢
可見(jiàn), 使用lazy可以把最后的計(jì)算拖到真正需要的時(shí)刻再進(jìn)行. 這種優(yōu)化非常適合在result遍歷的時(shí)候, 有需要退出的情況.
二. Optional
1.guard比if好的地方: guard let的變量可以被外部訪問(wèn), 避免了if金字塔結(jié)構(gòu); guard的語(yǔ)義更加鮮明, 就是為了檢查返回失敗條件的
- 關(guān)于optional chaining的結(jié)果也是optional的解釋:
let j = Int(“1”)?.successor().successor() // 為什么第二個(gè)successor()不需要加?來(lái)調(diào)用
原因在于結(jié)果是optional, 而不是中間狀態(tài)也是optional, 對(duì)于上面的語(yǔ)句來(lái)說(shuō), optional的狀態(tài)是已經(jīng)captured, 所以后續(xù)的方法調(diào)用只要不是前一個(gè)方法本身返回optional, 就不需要寫(xiě)?, 舉一個(gè)例證:
let j = Int(“1”)?.successor() // 這里把optional傳遞給了結(jié)果, 所以下面的語(yǔ)句需要加?
let k = j?.successor()
- 關(guān)于??操作符的解釋:
??操作符的作用基本可以等效為ObjC里面的?:操作符. 但是參考以下情況:
let i: Int? = nil
let j: Int? = nil
let k: Int? = 42
let m = i ?? j ?? k ?? 0
let n = i ?? j ?? k
print(“\(m)”) // 說(shuō)明m的類(lèi)型是Int
print("\(n!)”) // 說(shuō)明n的類(lèi)型是Int?
m和n的區(qū)別說(shuō)明, 對(duì)于編譯器來(lái)說(shuō), 不i j k是否為nil, m是可以確定不為nil的, 所以m不會(huì)為optional, 但是n則不一定. 這也算是optional的智能之處
另外, 用??來(lái)替代||和&&
if let n = i ?? j {
// 類(lèi)似于 if i != nil || j != nil
}
if let n = i, m = j {
// 類(lèi)似于 if i != nil && j != nil
}
主要注意的是, ??操作符要和多層optional一起使用的時(shí)候要特別注意, 如:
let s1: String?? = nil
(s1 ?? "inner") ?? “outer” // 返回 “inner"
let s2: String?? = .Some(nil)
(s2 ?? "inner") ?? “outer” // 返回 “outer"
4.Optional的map與flatMap
let stringNumbers = ["a","1", "2", "3"]
let x = stringNumbers.first.map{Int($0)} // x的類(lèi)型為Int??
let y = stringNumbers.first.flatMap{Int($0)} // y的類(lèi)型為Int?
- Optional類(lèi)型轉(zhuǎn)換
在Optional值與非Optional值進(jìn)行比較的時(shí)候, Swift會(huì)對(duì)非Optional值進(jìn)行類(lèi)型轉(zhuǎn)換, 以使兩者類(lèi)型匹配, 再進(jìn)行比較. 這個(gè)特性被廣泛使用, 例如下面的代碼:
let strArray = [“1”, “2”, “3"]
let result = strArray.first.map{$0}
result的類(lèi)型會(huì)是String?, 但是map中返回的類(lèi)型是String, 所以是由Swift的編譯器為我們進(jìn)行了類(lèi)型轉(zhuǎn)換.
6.強(qiáng)制解包
無(wú)論出于什么樣的目的這么干, 一定要反思一下, 是否已經(jīng)沒(méi)有更好的選擇了? 這么寫(xiě)之后最好能留下注釋解釋為什么.
7.隱式Optional
隱式Optional本質(zhì)上還是Optional, 只是在使用的時(shí)候不需要再解包而已, 聲明如下:
var s :Int! = nil
print(“(s)”) // 不會(huì)報(bào)錯(cuò)
一般情況下, 會(huì)在那些的確有可能為空, 但是一旦初始化完成之后就不會(huì)為空的變量使用此類(lèi)型. 常見(jiàn)于某些提供了可能失敗的構(gòu)造器的情況.
需要注意的是, 如果隱式Optional為nil, 對(duì)它進(jìn)行的任何操作同樣會(huì)造成運(yùn)行時(shí)error.
最后提一下Monad和Factor吧. 這個(gè)唐巧在自己的博客上更新了很多相關(guān)內(nèi)容, 貌似最新的Qcon講的也是這個(gè). 這個(gè)東西理解起來(lái)的確很難, 但其實(shí)也就是2個(gè)概念, 對(duì)于這2個(gè)概念的解釋, 我覺(jué)得唐巧的博客里面講的很細(xì)致, 一起分享給大家我認(rèn)為最核心的部分:
- 主要理解什么叫「封裝過(guò)的值」, 值被包含在容器中或者被Optional包含, 都可以理解為封裝過(guò)的值.
- flatMap和map都是處理封裝過(guò)的值, 前者的閉包接受一個(gè)「未封裝的值」瘩例,返回一個(gè)「封裝后的值」, 后者閉包接受一個(gè)「未封裝的值」澄成,返回一個(gè)「未封裝的值」.
理解起來(lái)是比較繞, 但是一般來(lái)說(shuō)看看源碼, 知道這2個(gè)高級(jí)函數(shù)有什么用就會(huì)容易理解很多.
另外, Advanced Swift這本書(shū)還是挺值得看的, 很多內(nèi)容的確比較新穎, 會(huì)看到很多國(guó)內(nèi)的大牛都講了里面的一部分東西, 這里面算是集大成之作. 后續(xù)的幾章因?yàn)闀簳r(shí)團(tuán)隊(duì)還沒(méi)有用Swift開(kāi)發(fā), 所以還沒(méi)看, 對(duì)類(lèi)和結(jié)構(gòu)體的那一章也是老生常談, 如果發(fā)現(xiàn)有新大陸會(huì)更新出來(lái).