2015-12-21 55 views
13

我們正在儘可能使用Swift結構。我們也在使用RxSwift,它有一些關閉的方法。當我們有一個結構創建一個指向self的閉包時,它會創建一個strong reference cycleSwift Struct內存泄漏

import Foundation 
import RxSwift 

struct DoesItLeak { 

    var someState: String = "initial value" 
    var someVariable: Variable<String> = Variable("some stuff") 

    let bag = DisposeBag() 

    mutating func someFoo() { 

     someVariable.subscribeNext { person in 

      self.someState = "something" 
     } 
     .addDisposableTo(bag) 
    } 
} 

我怎麼知道這個?如果我創建100,000個DoesItLeak對象並在它們的每一個上調用someFoo(),我相信我有100,000個具有強引用週期的對象。換句話說,當我擺脫含有這些對象的DoesItLeak數組時,這些對象會留在內存中。如果我不叫someFoo(),那沒有問題。

變量是一個類。所以,我可以在可變<字符串使用Xcode的儀器的分配和過濾看到這個內存問題>

Filtering By Variable

enter image description here

如果我嘗試使用[弱自我]比如在下面,我得到一個編譯錯誤:

someVariable.subscribeNext { [weak self] person in 

編譯器錯誤是「弱不能適用於非類類型」

在真實/非示例代碼中,我們通過self訪問方法和變量,這是一個內存問題。

如何解決這個內存問題,同時保持DoesItLeak結構?

感謝您的幫助。

+1

堅持使用結構可能違反了這個**在類和結構之間進行選擇**指南:「有理由期望當你指定或繞過一個結構體時,封裝值將被複制而不是被引用該結構的實例。「 - https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/ClassesAndStructures.html – finneycanhelp

+2

我不認爲你有內存泄漏 - 至少不是由於使用自我關閉造成的內存泄漏引用一個結構。從我所知道的情況來看,當你使用self來引用閉包中的一個結構體時,它只會構造一個結構體的副本 - 它不會創建對該結構體的引用。一個強大的參考週期將不得不涉及類和閉包,而不是結構。 –

+2

「Variable」類型是類還是結構? –

回答

4

由於Darren在評論中提到:「DoesItLeak can't be a struct」我們不能讓DoesItLeak成爲一個結構體並且可以安全地解決強參考循環問題。

類似結構的值類型存在於堆棧幀中。閉包和類是參考類型。

作爲Strong Reference Cycles for Closures section所說:

This strong reference cycle occurs because closures, like classes, are reference types.

由於結構有Variable和封閉參照self存儲到使用subscribeNextVariable類,它創建強基準週期。請參閱Automatic Reference Counting Apple文檔中的「解決關閉的強參考週期」。