2016-04-21 41 views
0

在Swift中我們可以使用ObjC中沒有的很好的特性:可以在任何地方使用閉包。但它可能導致保留週期。看看這個例子:保留循環發生在傳遞方法而不是閉包時

import Foundation 

class C1 { 
    let closure: Void -> Void 
    init(closure: Void -> Void) { 
     self.closure = closure 
    } 

    deinit { 
     print("C1 deinit") 
    } 
} 

class C2 { 
    var c1: C1! 

    func initializeC1() { 
     c1 = C1(closure: f) 
    } 

    func f() {} 

    deinit { 
     print("C2 deinit") 
    } 
} 

func main() { 
    let c2 = C2() 
    c2.initializeC1() 
} 

main() 

這裏我們創建了C2-> C1-> f-> C2的循環。如果你運行這個程序,deinit將不會被調用。但是,如果您將f替換爲initializeC1{},例如,它將會是。

對於常規關閉,我們可以使用捕獲列表來避免強大的保留,但看起來你不能將它們用於方法。 所以,問題是:在這種情況下,我們怎麼能打破保留週期,有沒有可能?

回答

3

當然,我們可以通過在封閉包裝它像這樣「weakify」綁定方法:

import Foundation 

class C1 { 
    let closure: Void -> Void 
    init(closure: Void -> Void) { 
     self.closure = closure 
    } 

    deinit { 
     print("C1 deinit") 
    } 
} 

class C2 { 
    var c1: C1! 

    func initializeC1() { 
     // HERE we wrap a method call into a closure to break retain-cycle. 
     c1 = C1(closure: { [weak self] in 
      self?.f() 
     }) 
    } 

    func f() {} 

    deinit { 
     print("C2 deinit") 
    } 
} 

func main() { 
    let c2 = C2() 
    c2.initializeC1() 
} 

main() 
//C2 deinit 
//C1 deinit 
+0

尼斯的答案,但我們又重新回到了封閉的語法再次,我試圖避免。如果沒有更好的解決方案,它會被接受的答案。 –

+0

我沒有在文檔中看到明確的聲明,但似乎這些方法在Swift中被綁定到它們的實例,我們無法改變這種行爲。我也沒有看到一種方法來製作一個漂亮的實用程序來克服這個限制。 – werediver

相關問題