5

これは漏れない理由を説明できますか?スウィフト - 密閉状態で強く捉えた後のリークを期待してください

closureの中にselfをキャプチャしているので、2つの強力なポインタが互いに指しているので、deinitメッセージはPersonオブジェクトに対して呼び出されるべきではありません。

まず、これは人私のクラスです:

class Person { 
    var name: String 
    init(name: String) { self.name = name } 
    deinit { print("\(name) is being deinitialized") } 
} 

そして、これが私ののViewControllerの実装です:私はやって問題を解決することができるように期待していた

class ViewController: UIViewController { 

    var john:Person? 

    func callClosureFunction(closure:(name:Bool) ->()) { 
     closure(name: true) 
    } 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     john = Person(name:"John") 

     self.callClosureFunction { (name) in 

      self.john?.name = "John Appleseed" 
      self.john = nil 

      // xcode prints - John Appleseed is being deinitialized 
     } 

    } 

} 

self.callClosureFunction { [weak self] (name) in ... 

しかしそれは必要でもありませんでした。どうして?

答えて

3

ビューコントローラはを保持していませんので、クロージャには循環参照はありません。あなたがこれを書いた場合:

class ViewController: UIViewController { 

    var john:Person? 
    var closure:(Bool)->()? 

    func callClosureFunction(closure:((name:Bool) ->())?) { 
     closure?(name: true) 
    } 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     john = Person(name:"John") 
     closure = { (name) in 

      self.john?.name = "John Appleseed"  

      // Because this closure will never be released, the instance of Person will never deinit either 
     } 
     self.callClosureFunction(closure) 
    } 
} 

は、ビューコントローラは、閉鎖を維持するだろうし、閉鎖はselfへの参照を経由してビューコントローラを維持するだろう。したがって、いずれも解放されず、明示的にself.john = nil(元の例で行った)を設定しなかった場合、Personインスタンスはdeninitという名前のコールを受け取りません。

閉鎖時に弱いものを使用することはよくありません(実際には不明なバグにつながる可能性があります)。覚えておくべき重要なルールは、弱参照は一般的にARCのデフォルトではないということです。保持サイクルがになる場合を除き、Strongはデフォルトのにする必要があります。この場合、weakはその循環参照を破るためにのみ使用してください。クロージャーと同じです:selfでなければなります。 selfもクロージャー自体に強い参照があります。

+1

「John Appleseed」の「Person」オブジェクトは依然として除外されます。私の答えを参照してください – Alexander

+0

@AlexanderMomchliovクロージャがVC(自己)を保持し、VCが私の例のようにクロージャを保持する場合、VCは決して解放されません(クロージャもありません)。 VCが決して脱調しない場合、Personオブジェクトへの参照を解放することは決してありません。これは、Personオブジェクトが決してdeinitしないことを意味します。 –

+1

保持サイクルがあるかどうかは関係ありません。 'john'は明示的に' nil'に設定され、最後の参照を削除します。これにより、ARCは 'deinit'を行います。 – Alexander

0

あなたはViewControllerを指しているselfをキャプチャしていますが、Personインスタンスについては不思議です。

Personは、実際には循環参照されていないため、閉鎖の終わりにnilに設定すると、非活性化され、解放されます。

ViewControllerdeinitを実装し、その動作を確認してください。

0

私は閉鎖内で自己をキャプチャしているので、互いに指し示す2つの強力なポインタを持つことになるので、deinitメッセージはPersonオブジェクトに対して呼び出されるべきではありません。

いいえ、あなたは、閉鎖からselfに、1つの強力なポインタを持っています。クロージャーからはselfへの循環参照はありません。したがって、あなたはdirected acylic graphですが、これはARCにとって問題ありません。

しかし、あなたの実験には手がかりがありません。クロージャがキャプチャされたとしても、John AppleseedPersonオブジェクトはまだdeinitになります。このオブジェクトのライフサイクルは、ViewControllerjohnリファレンスにのみ依存しています。その参照をnilに設定すると、John Appleseedオブジェクトへの最後の参照が削除されるため、初期化されません。

関連する問題