当一个方法传递给一个带闭包的函数时,我可以在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行,如果我将doNothing
替换为{ [unowned self] notif in self.doNothing(notif) }
,强引用就会消失。
有什么想法吗?
答案 0 :(得分:2)
如何在避免强烈引用的同时使用它?
你不能。
只有内联定义的匿名函数(在使用点)才能有捕获列表(例如[unowned self]
)。因此,只有匿名函数才能提供您要求的功能。用func
定义的函数根本无法做到。
这只是关于斯威夫特的事实。
(可能存在潜在的原因;我怀疑原因与存储有关。func
函数以某种方式静态存储。但是内联定义的匿名函数不是;它产生了在它被传递给被调用者的那一刻。但这只是一个猜测,而且是一个相当含糊的猜测。)
答案 1 :(得分: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编译让你使用函数而不是闭包是不安全的,因为它总会在你的项目中留下内存泄漏。