Swift: 分配一个class方法给一个handler和handling weak self
Swift: Assign a class method to a handler and handling weak self
我刚刚在我正在开发的应用程序中寻找内存泄漏,并注意到以下内容会产生内存泄漏:
class SubClass {
var didCloseHandler: (() -> Void)?
}
class MainClass {
var subClass = SubClass()
func setup {
subClass.didCloseHandler = self.didCloseSubClass
}
func didCloseSubClass() {
//
}
}
这会产生一个保留循环,并且有充分的理由 - didCloseHandler
强烈捕获 MainClass,而 MainClass 强烈捕获 SubClass。
我的问题:Swift 中有没有一种方法允许我在没有保留周期的情况下将 class 方法分配给处理程序?
是的,我知道我可以使用 subClass.didCloseHandler = { [weak self] self?.didCloseSubClass() }
来做到这一点。不过,我想知道是否可以在不引入新闭包的情况下完成。
在MainClass中弱引用子类
如果您在其他地方没有对 SubClass 实例的强引用 - 您可以尝试这样的包装器:
func WeakPointer<T: AnyObject>(_ object: T, _ method: @escaping (T) -> () -> Void) -> (() -> Void) {
return { [weak object] in
method(object!)()
}
}
然后像这样使用它:
func setup() {
subClass.didCloseHandler = WeakPointer(self, MainClass.didCloseSubClass)
}
如果您在 didCloseSubClass
实现中不需要 MainClass 实例的属性 - 您可以制作此方法 static
,这也将解决您的问题。
如果您在其他地方有对 SubClass 实例的强引用并且不会立即释放它 - weak var subClass
会这样做,正如已经提到的那样。
编辑:
我想出了另一个主意。它可能看起来有点复杂,但也许会有所帮助。
import Foundation
class SubClass {
@objc dynamic func didCloseHandler() {
print(#function)
}
deinit {
print(" \(self) deinit")
}
}
class MainClass {
var subClass = SubClass()
func setup() {
if let implementation = class_getMethodImplementation(MainClass.self, #selector(didCloseSubClass)),
let method = class_getInstanceMethod(SubClass.self, #selector(SubClass.didCloseHandler)) {
method_setImplementation(method, implementation)
}
}
@objc func didCloseSubClass() {
print(#function)
}
deinit {
print(" \(self) deinit")
}
}
您更改 @objc dynamic
方法的闭包并将其实现设置为 setup()
中 MainClass 的实现。
我刚刚在我正在开发的应用程序中寻找内存泄漏,并注意到以下内容会产生内存泄漏:
class SubClass {
var didCloseHandler: (() -> Void)?
}
class MainClass {
var subClass = SubClass()
func setup {
subClass.didCloseHandler = self.didCloseSubClass
}
func didCloseSubClass() {
//
}
}
这会产生一个保留循环,并且有充分的理由 - didCloseHandler
强烈捕获 MainClass,而 MainClass 强烈捕获 SubClass。
我的问题:Swift 中有没有一种方法允许我在没有保留周期的情况下将 class 方法分配给处理程序?
是的,我知道我可以使用 subClass.didCloseHandler = { [weak self] self?.didCloseSubClass() }
来做到这一点。不过,我想知道是否可以在不引入新闭包的情况下完成。
在MainClass中弱引用子类
如果您在其他地方没有对 SubClass 实例的强引用 - 您可以尝试这样的包装器:
func WeakPointer<T: AnyObject>(_ object: T, _ method: @escaping (T) -> () -> Void) -> (() -> Void) {
return { [weak object] in
method(object!)()
}
}
然后像这样使用它:
func setup() {
subClass.didCloseHandler = WeakPointer(self, MainClass.didCloseSubClass)
}
如果您在 didCloseSubClass
实现中不需要 MainClass 实例的属性 - 您可以制作此方法 static
,这也将解决您的问题。
如果您在其他地方有对 SubClass 实例的强引用并且不会立即释放它 - weak var subClass
会这样做,正如已经提到的那样。
编辑: 我想出了另一个主意。它可能看起来有点复杂,但也许会有所帮助。
import Foundation
class SubClass {
@objc dynamic func didCloseHandler() {
print(#function)
}
deinit {
print(" \(self) deinit")
}
}
class MainClass {
var subClass = SubClass()
func setup() {
if let implementation = class_getMethodImplementation(MainClass.self, #selector(didCloseSubClass)),
let method = class_getInstanceMethod(SubClass.self, #selector(SubClass.didCloseHandler)) {
method_setImplementation(method, implementation)
}
}
@objc func didCloseSubClass() {
print(#function)
}
deinit {
print(" \(self) deinit")
}
}
您更改 @objc dynamic
方法的闭包并将其实现设置为 setup()
中 MainClass 的实现。