閉包的特點(diǎn)
swift的iOS的app中状勤,遍布著各種閉包吴侦,閉包中經(jīng)常出現(xiàn)捕獲列表挖胃,我們經(jīng)常用[weak self]來防止內(nèi)存泄露杂靶。我們都知道swift閉包捕獲的是引用,但是swift閉包任何時(shí)候都是捕獲變量的引用嗎酱鸭?并不是吗垮!
現(xiàn)在我們來看一個(gè)簡單的例子:
var a = 0
var b = 0
let closure : () -> () = { print(a, b) }
執(zhí)行閉包
closure() ? // 0 0
改變 a, b 的值
a = 3
b = 7
再次調(diào)用
closure()? // 3 7
我們可以很直觀的看到現(xiàn)在的a,b值都改變了。swift的閉包中捕獲到的值是捕獲的引用凹髓。所以一旦你改變了這些捕獲變量的值烁登,在閉包中就會(huì)反應(yīng)出來。
引用類型帶來的問題
事實(shí)上蔚舀,很多時(shí)候饵沧,閉包的特性并不總是那么直觀,如果不仔細(xì)赌躺,很容易帶來一些奇怪的錯(cuò)誤狼牺。比如,我們創(chuàng)建一個(gè)Array礼患,然后數(shù)組的類型是閉包
var arrayClosure : ?[() -> ()] = []
然后我們執(zhí)行下面的代碼是钥,將閉包添加到數(shù)組中
var i = 0
for _ in 1...3 {
arrayClosure.append { print(i) }
?i += 1
}
我們嘗試條用數(shù)組中的三個(gè)閉包來看看最后的打印值:
arrayClosure[0]()// 3
arrayClosure[1]()// 3
arrayClosure[2]()// 3
和我們預(yù)想的不太一樣哈,閉包打印的值竟然都是最后一次的值缅叠。意味著三個(gè)閉包引用的都是最后一次的i的值悄泥。事實(shí)上我們想要的值或許是1,2肤粱,3弹囚。想象一下,如果三個(gè)閉包每次捕獲的都是每次i的值的副本狼犯。那么是不是會(huì)打印出1余寥,2领铐,3的結(jié)果?但是閉包捕獲的是引用呀宋舷,怎么才能獲取copy副本呢绪撵。沒錯(cuò),就是捕獲列表祝蝠。
好了音诈,現(xiàn)在我們再看另一個(gè)例子,看起來和開篇的第一個(gè)例子差不多,但是這里我們加了"?[c, d] in " 绎狭,關(guān)鍵字 in 的左邊就是我們的重點(diǎn)细溅,這里表示的不是數(shù)組,而是捕獲列表儡嘶。一旦用了捕獲列表喇聊,閉包捕獲的將不是原始值的引用,而是在閉包內(nèi)部詭異的生成了一個(gè)原始值的copy副本蹦狂。
var c = 0
var d = 0
let anotherClosure : () -> () = { ?[c, d] ?in
print(c, d)
}
c = 3
d = 7
調(diào)用閉包誓篱,我們看看打印結(jié)果:
anotherClosure() // 0, 0
所以,顯而易見凯楔,當(dāng)你使用了捕獲列表之后窜骄,你無論怎么在閉包外面操作改變原始的值。閉包并不關(guān)心摆屯。因?yàn)檫@個(gè)時(shí)候它已經(jīng)不是捕獲的引用了邻遏,而是最初原始值的copy副本。所以文中的第二個(gè)例子如果想得到1虐骑,2准验,3的結(jié)果。使用捕獲列表就完全可以解決富弦,perfect沟娱!
所以對于swift的閉包而言,并不總是捕獲的引用矫废。這篇先到這里盏缤,文筆不好,大家多多關(guān)照(*^__^*)?