2016-11-04 9 views
1

メソッドをクロージャを受け取る関数に渡すときに、someFunc(){[unowned self] in self.someMethod()} `のいずれかを使用できます。メソッドを関数に渡すときに強い参照を避ける

最初の文字は短い文字ですが、参考になります。この強力な参照を避けてどのように使用できますか?ここで

が漏れて1と良いものの両方でのデモです: https://swiftlang.ng.bluemix.net/#/repl/581ccd3a0bdc661a6c566347

import Foundation 

private var instanceCounter = 0 

class Leak : NSObject { 

    override init() { 
     super.init() 
     instanceCounter += 1 
    } 

    deinit { 
     instanceCounter -= 1 
    } 
} 

class OnFunctionLeak : Leak { 

    override init() { 
     super.init() 
     _ = NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: "OnFunctionLeak"), 
               object: nil, 
               queue: nil, 
               usingBlock: doNothing) 
    } 

    func doNothing(_ notif: Notification) { } 

    deinit { 
     NotificationCenter.default.removeObserver(self) 
    } 
} 

class OnClosureLeak : Leak { 

    override init() { 
     super.init() 
     _ = NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: "OnFunctionLeak"), 
               object: nil, 
               queue: nil) { [unowned self] notif in 
      self.doNothing(notif) 
     } 
    } 

    func doNothing(_ notif: Notification) { } 

    deinit { 
     NotificationCenter.default.removeObserver(self) 
    } 
} 

var onFunctionLeak: OnFunctionLeak? = OnFunctionLeak() 
onFunctionLeak = nil 

//XCTAssertEqual(instanceCounter, 0) 
print("instanceCounter: \(instanceCounter) == 0") 

instanceCounter = 0 
var onClosureLeak: OnClosureLeak? = OnClosureLeak() 
onClosureLeak = nil 

//XCTAssertEqual(instanceCounter, 0) 
print("instanceCounter: \(instanceCounter) == 0") 

短い方の選択肢がライン26上にあり、私は{ [unowned self] notif in self.doNothing(notif) }doNothingを交換する場合、強い参照がなくなっています。

アイデア?

+0

関連する:「メソッドからのクロージャから強い参照サイクルを削除する方法」(http://stackoverflow.com/q/39899051/2976878)「自分自身への強い参照を避けるより良い方法があるとは思わない'あなたの2番目の例のようにクロージャを使わずに。 – Hamish

+0

私はそれを読んで、私は確信しています。しかし、それが確認されれば、私の考えはなぜそれが常に隠れている強い参照を作成する場合は、質問を直接書くことができますので、簡単に間違いをすることができます。 – Dam

+0

ところで、 "NotificationCenter.default.removeObserver(self)"を呼び出すことは、一般的に悪い習慣とみなされます。これは、親クラスを混乱させる可能性があるため、Appleはあなたの観測結果を1つずつ削除することをお勧めします。 –

答えて

1

この強力なリファレンスを回避するにはどうすれば使用できますか?

できません。

(使用時点で)インラインで定義された匿名関数は、キャプチャリスト(たとえば、[unowned self])を持つことができます。したがって、匿名関数だけがあなたが求めている機能を提供することができます。 funcで定義された関数は単純にそれを行うことはできません。

これはスウィフトの事実です。 関数は何らかの方法で静的に格納されていますが、インラインで定義された匿名関数はそうではなく、正確にはそれは被告に渡される瞬間ですが、それは単なる推測であり、それはむしろあいまいです。)

0

マットが正しいですし、強力な参照なしに関数を使用する方法を見つけることができません。

varを使ってよりきれいにすることができます。関数内に直接クロージャを書くことは本当にきれいではありません。あなたは強い参照を持っていない、あなたは「:doSomethingの)を使用して」行うことができますよう

class OnVarLeak : Leak { 

    var value = 0 

    override init() { 
     super.init() 
     NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: "OnVarLeak"), 
               object: nil, 
               queue: nil, 
               using: doNothing) 
    } 

    var doNothing: (Notification) -> Void { 
     return { [unowned self] notif in 
      self.value += 1 
     } 
    } 

    deinit { 
     NotificationCenter.default.removeObserver(self) 
    } 
} 

スウィフトコンパイルでは、プロジェクトでメモリリークが常に発生するため、クロージャの代わりに関数を使用するのは安全ではないと私は考えています。

関連する問題