如何解决当回调数组不再有调用者时,如何自动从回调数组中删除回调?
我有这些课程:
class Callback {
let callback: () -> Void
init(callback: @escaping () -> Void) {
self.callback = callback
}
}
class CallbackContainer {
private var callBacks = [Callback]()
func add(callback: @escaping () -> Void) -> Callback {
let cl = Callback(callback: callback)
callBacks.append(cl)
return cl
}
func callAll() {
for callback in callBacks {
callback.callback()
}
}
}
class Container {
let callbackContainer = CallbackContainer()
func executeSomeLongTasks() {
dispatchQueue.main.asyncAfter(deadline: .Now() + 5) {[weak self] in
self?.callbackContainer.callAll()
}
}
}
class AViewController: UIViewController {
var callback: Callback?
let container: CallbackContainer
init(container: CallbackContainer) {
self.container = container
super.init(nibName: nil,bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
callback = container.add {
debugPrint("Called callback on A")
}
}
deinit {
debugPrint("Deinited AViewController")
}
}
我希望 CallbackContainer
在没有人再调用时自动删除回调。例如:
let container = Container()
var aVC: AViewController? = AViewController(container: container.callbackContainer)
//on somewhere executed long task
container.executeSomeLongTasks()
aVC = nil
// should not call callback here
这里,当 aVC
被释放时 - 比如 aVC = nil
或从导航堆栈中弹出 - 那么存储在 callbackContainer
中的回调(在 AViewController viewDidload()
上创建),应该被删除自动从内部数组中删除,无需在 AViewController deinit()
上手动删除它。因此,不会再从 CallbackContainer.callAll()
它应该像 disposeBag
上的 RxSwift
一样工作。我看到了 disposeBag
代码,但不明白。
有人知道吗?
解决方法
你需要的是一种弱数组。据我所知,Swift 基础类中没有这样的类型:我的第一个想法是使用 NSMapTable
或类似 weakToStrongObjects
配置的东西,它被记录为将键存储为弱引用,但不幸的是,该类不会自动重新组织,请参阅 discussion part:
不推荐使用从弱到强的映射表。被清零的弱键 > 的强值将继续保持,直到映射表调整自身大小。
你可以做的是:
- 创建一个存储弱引用和闭包的装箱对象
- 将该框添加到
callBacks
数组中。 - 调用
callAll
时,首先清理callBacks
数组以移除所有带有nil
引用的框。
手动清理是一个缺点,因为当弱引用由 ARC 引导时,您不会收到通知。但它是由Container集中完成的,所以客户端不需要关心。
例如:
nil
然后,在 typealias CallbackType = () -> Void
class WeakCallback : Equatable {
let id = UUID()
weak var refItem: AnyObject?
let callback:CallbackType
init(refItem: AnyObject,callback:@escaping CallbackType) {
self.refItem = refItem
self.callback = callback
}
static func == (lhs: WeakCallback,rhs: WeakCallback) -> Bool {
return lhs.id == rhs.id
}
}
class CallbackContainer {
var callBacks = [WeakCallback]()
func add(ref:AnyObject,callback: @escaping () -> Void) -> WeakCallback {
cleanupCallbackArray()
let cl = WeakCallback(refItem:ref,callback: callback)
callBacks.append(cl)
return cl
}
func callAll() {
cleanupCallbackArray()
for cb in callBacks {
if (cb.refItem != nil) {
cb.callback()
} else {
print ("oops,found nil for \(cb.id)")
}
}
}
func cleanupCallbackArray() {
callBacks = callBacks.filter { cb -> Bool in
if (cb.refItem == nil) {
print ("\(cb.id) has nil reference,will be removed")
return false
}
return true
}
}
}
中,添加视图控制器作为对容器的引用:
viewDidLoad
测试:
override func viewDidLoad() {
super.viewDidLoad()
callback = container.add (ref:self) {
debugPrint("Called callback on A")
}
}
给出:
callAll 1
“在 A 上调用回调”
设置为零
“定义的 AViewController”
callAll 2
81C3D375-4B0E-4806-8088-AFE81C3125F3 没有参考,将被删除
如您所见,不会在“callAll 2”时调用闭包。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。