我們先從一個範例開始‧
下面這段 code 雖然沒有 leak‧
實際上 closure 已經造成 strong capture self
再不修改 closure 的情況下,我們只需要一些改動就會造成 retain cycle
class C {
func test() {
let handler = {
print(self)
}
}
}
handler -> self -> handler
class C {
+ var handler: () -> ()
func test() {
- let handler = {
+ self.handler = {
print(self)
}
}
}
handler -> self -> handler
class C {
+ var handler: () -> ()
func test() {
let handler = {
print(self)
}
+ self.handler = handler
}
}
handler -> self -> sub -> handler
class C {
+ class Sub {
+ var handler: () -> ()
+ }
+ var sub: Sub?
func test() {
- let handler = {
- print(self)
- }
+ sub = Sub {
+ print(self)
+ }
}
}
weak self
)其實這個案例也是大家最常見遇到的 case‧
let handler = { [weak self] in
print(self)
}
weak
?Non-escaping closure 只會造成一次性使用,所以不用
[1, 2, 3].map { value in
return value + self.value
}
我們再拉回看剛剛的 handler
這三段 code 可以視為等價
也可以說第一種寫法造成 Implict Capture
let handler = {
print(self)
}
let handler = { [self] in
print(self)
}
let handler = { [self = self] in
print(self)
}
在內層使用 weak
就不會 strong capture?
let handler = {
let handler = { [weak self] in
print(self)
}
}
因為 closure 並不會平白無故就抓取變數
當 closure 在該層找不到變數的話
就抓取(Implict Capture)前一層closure
/function
的變數
如果前一層也沒有變數前一層
會向前前一層
抓取
依此類推
我們把上面的 code 加上編號的等價 code
就會發現 handler1 capture self
let handler1 = { [self1 = self] in
let handler2 = { [weak self2 = self1] in
print(self2)
}
}
每一層皆 capture self
主要是避免忘記需要 capture 這件事
let handler = { [weak self] in
let handler = { [weak self] in
print(self)
}
}
應該說第一層 capture self 即可
我們先展開成最完整的等價 code,如下
let handler1 = { [weak self1 = self] in
let handler2 = { [weak self2 = self1] in
let handler3 = { [weak self3 = self2] in
print(self3)
}
}
}
接著取消 handler2 的 capture
let handler1 = { [weak wself1 = self] in
let handler2 = { // [wself1]
let handler3 = { [weak wself3 = wself1] in
print(wself3)
}
}
}
最後的等價 code
let handler1 = { [weak self] in
let handler2 = {
let handler3 = { [weak self] in
print(self)
}
}
}
直接 capture weak self
weak var ws = self
let handler = {
let handler = {
print(ws)
}
}
另外一個會 capture self 的東西可比較少人注意到,也就是 instance function
instance function 其實是所謂的 Curry Function
用以下的 code 做展示
class Foo {
func hello() {
print("bar")
}
}
// Foo.hello
func Foo_Hello(_ `self`: Foo) -> () -> () {
return { [self] in
print("bar")
}
}
let foo = Foo()
foo.hello() // bar
let hello1 = Foo.hello(foo)
hello1() // bar
let hello2 = Foo_Hello(foo)
hello2() // bar
RX
rx
.subscribe(onNext: self.hello)
.disposed(by: bag)
Combime
cancellable = publisher
.sink(receiveCompletion: self.hello)
cancellable = publisher
.sink { [weak self] in
self?.hello()
}