将方法传递给函数时避免强引用
Avoiding strong reference when passing a method to a function
将方法传递给采用闭包的函数时,我可以使用 someFunc(closure: someMethod) or
someFunc() { [unowned self] in self.someMethod() }`.
第一个较短,但具有很强的参考意义。如何在避免这种强引用的情况下使用它?
这是一个既有泄漏的也有良好的演示:
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) }
,强引用将消失。
有什么想法吗?
How can I use it while avoiding this strong reference?
你不能。
只有内联定义的匿名函数(在使用时)可以有一个捕获列表(例如[unowned self]
)。因此,只有匿名函数才能提供您所要求的功能。用 func
定义的函数根本做不到。
这只是关于 Swift 的事实。
(可能有潜在的原因;我怀疑原因与存储有关。func
函数以某种方式静态存储。但是内联定义的匿名函数不是;它来自在它被传递给被调用者的那一刻成为存在。但这只是一个猜测,而且是一个相当模糊的猜测。)
Matt 是对的,如果没有强引用,我找不到使用函数的方法。
我刚刚发现你可以使用 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)
}
}
像这样你没有强引用,你可以"using: doSomething)"。
我仍然认为 Swift 编译让你使用函数而不是闭包是不安全的,因为它总是会在你的项目中留下内存泄漏。
将方法传递给采用闭包的函数时,我可以使用 someFunc(closure: someMethod) or
someFunc() { [unowned self] in self.someMethod() }`.
第一个较短,但具有很强的参考意义。如何在避免这种强引用的情况下使用它?
这是一个既有泄漏的也有良好的演示: 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) }
,强引用将消失。
有什么想法吗?
How can I use it while avoiding this strong reference?
你不能。
只有内联定义的匿名函数(在使用时)可以有一个捕获列表(例如[unowned self]
)。因此,只有匿名函数才能提供您所要求的功能。用 func
定义的函数根本做不到。
这只是关于 Swift 的事实。
(可能有潜在的原因;我怀疑原因与存储有关。func
函数以某种方式静态存储。但是内联定义的匿名函数不是;它来自在它被传递给被调用者的那一刻成为存在。但这只是一个猜测,而且是一个相当模糊的猜测。)
Matt 是对的,如果没有强引用,我找不到使用函数的方法。
我刚刚发现你可以使用 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)
}
}
像这样你没有强引用,你可以"using: doSomething)"。
我仍然认为 Swift 编译让你使用函数而不是闭包是不安全的,因为它总是会在你的项目中留下内存泄漏。