2016-11-04 52 views
1

将方法传递给需要闭包的函数时,我可以在self.someMethod()中使用someFunc(closure: someMethod) or someFunc(){[unowned self]}``。向函数传递方法时避免强引用

第一个较短,但有很强的参考价值。我怎样才能使用它,同时避免这个强烈的参考?

下面是两个泄漏一个良好的一个演示: 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)我不相信有一个更好的方法可以避免强烈提及“自我” '不使用闭包,例如在第二个例子中。 – Hamish

+0

我读过它,我要求确定。但是,如果它得到证实,我的想法就是为什么允许直接写出这个问题,如果它总是会创建一个隐藏的强参考,那么容易犯这个错误。 – Dam

+0

顺便说一句,调用“NotificationCenter.default.removeObserver(self)”通常被认为是不好的做法 - 这可能会弄乱父类,所以Apple鼓励你逐个删除你的观察结果。 –

回答

1

我该如何使用它,同时避免这种强烈的参考?

你不行。

只有内联定义的匿名函数(在使用点)可以有一个捕获列表(如[unowned self])。因此,只有匿名函数才能提供您所要求的功能。用func定义的函数根本无法做到。

这只是关于Swift的一个事实。我们怀疑这个原因与存储有关,func函数是以某种方式静态存储的,但是一个内联的匿名函数并不是;它在但这只是一个猜测,而且是一个相当模糊的猜测)

0

马特是对的,我找不到一个方法来使用没有强引用的函数。

我刚刚发现你可以使用var来使它更简洁直接在你的函数里面写闭包并不是很干净。

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) 
    } 
} 

就像你没有强烈的参考,你可以做“使用:doSomething”)。

我仍然认为Swift编译让你使用函数而不是闭包是不安全的,因为它总会在你的项目中留下内存泄漏。