我對閉包的理解是,它會強烈地捕獲所有直接參考的物件,而不管物件變數是宣告的weak還是strong在閉包之外,如果我們想弱捕獲它們,那么我們需要顯式定義一個捕獲串列并weak在其中標記它們捕獲串列。
obj?.callback = { [weak obj] in
obj?.perform()
}
但是在我的測驗中,我發現如果變數已經weak在閉包之外,那么我們就不需要使用捕獲串列來弱捕獲它了。
class Foo {
var callback: (() -> ())?
init() {
weak var weakSelf = self
callback = {
weakSelf?.perform()
}
// is above equivalent to below in terms of memory management?
// callback = { [weak self] in
// self?.perform()
// }
}
func perform() {
print("perform")
}
deinit {
print("deinit")
}
}
let foo = Foo() // prints "deinit foo"
The above snippet is not creating any retain cycle. Does this mean we don't need to explicitly capture an object variable weakly in capture list if the variable is already declared weak and capture list just provides syntactical advantage over creating a weak variable before using them inside closure.
uj5u.com熱心網友回復:
有點,在這個具體的例子中,但你需要非常小心你如何看待正在發生的事情。
首先,是的,這是相同的。我們可以通過生成 SIL ( swiftc -emit-sil main.swift) 來判斷這一點。除了selfvs的名稱不同外weakSelf,它們生成完全相同的未優化 SIL。為了更清楚,我將更改捕獲串列中變數的名稱(這只是重命名,不會改變行為):
弱自我
weak var weakSelf = self
callback = {
weakSelf?.perform()
}
弱自我
callback = { [weak weakSelf = self] in
weakSelf?.perform()
}
比較它們
$ swiftc -emit-sil weakSelf.swift > weakSelf.sil
$ swiftc -emit-sil weak_self.swift > weak_self.sil
$ diff -c weakSelf.sil weak_self.sil
*** weakSelf.sil 2022-03-27 10:58:13.000000000 -0400
--- weak_self.sil 2022-03-27 11:01:22.000000000 -0400
***************
*** 102,108 ****
// Foo.init()
sil hidden @$s4main3FooCACycfc : $@convention(method) (@owned Foo) -> @owned Foo {
! // %0 "self" // users: , %8, %7, %2, ", %1
bb0(%0 : $Foo):
debug_value %0 : $Foo, let, name "self", argno 1, implicit // id: %1
%2 = ref_element_addr %0 : $Foo, #Foo.callback // user: %4
--- 102,108 ----
// Foo.init()
sil hidden @$s4main3FooCACycfc : $@convention(method) (@owned Foo) -> @owned Foo {
! // %0 "self" // users: %8, %7, , %2, ", %1
bb0(%0 : $Foo):
debug_value %0 : $Foo, let, name "self", argno 1, implicit // id: %1
%2 = ref_element_addr %0 : $Foo, #Foo.callback // user: %4
除了用戶評論的順序之外self,它們是相同的。
But be very, very careful with what you do with this knowledge. This happens to be true because there exists a strong reference to self elsewhere. Going down this road too far can lead to confusion. For example, consider these two approaches:
// Version 1
weak var weakObject = Object()
let callback = {
weakObject?.run()
}
callback()
// Version 2
var weakObject = Object()
let callback = { [weak weakObject] in
weakObject?.run()
}
callback()
These do not behave the same at all. In the first version, weakObject is already released by the time callback is created, so callback() does nothing. The compiler will generate a warning about this, so in most cases this is an unlikely bug to create, but as a rule you should generally do weak captures in the capture list so that it occurs as close to the closure creation as possible, and won't accidentally be released unexpectedly.
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/450995.html
標籤:ios swift memory-management retain-cycle
