如何防止在 GCD 中释放对象?
How to prevent deallocated objects in GCD?
此函数应该重新安排工作项的执行:
class MyClass {
var id: String?
var workItem: DispatchWorkItem?
var isDoing = false
func myFunction() {
guard let id = self.id else { return }
isDoing = true
NotificationCenter.default.post(name: MyNotification, object: nil, userInfo: ["id": id])
workItem?.cancel()
workItem = DispatchWorkItem {
self.isDoing = false
NotificationCenter.default.post(name: MyNotification, object: nil, userInfo: ["id": id])
}
if let workItem = workItem {
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + DispatchTimeInterval.seconds(10), execute: workItem)
}
}
}
它在开发中工作正常,但设计似乎可疑,所以我问一些基本问题:
- 如果
workItem?.cancel()
在队列试图执行 workItem
之前被调用,workItem
可能是零吗?
- 当执行
workItem
时,workItem
中的 id
是否可以为零,或者它是否被范围 let id = self.id
保留?
- 如果
MyClass
对象已被释放,那么在执行 workItem
时,workItem
中的 isDoing
是否已经被释放?换句话说,当 MyClass
对象被释放时,调度的 workItem
会发生什么?
不太清楚你的意思。你不会在任何地方取消 workItem
。
不,它不能是 nil
,因为您正在使用局部变量 - self.id
的副本。通过使用 guard
可以确保局部变量 id
不为 nil,并且闭包保持对捕获值的强引用(默认情况下),因此它不会被释放。
isDoing
是 MyClass
的一个实例变量,所以它不能在 MyClass
实例被释放之前被释放。问题是,在你的情况下 MyClass
不能被释放,因为你正在寻找一个强大的参考周期。默认情况下,闭包保持对捕获值的强引用,并且您正在捕获 self
。并且由于 self
保持对 workItem
的强引用,这反过来又保持对捕获 self
的闭包的强引用,因此引用循环。
通常,当捕获 self
时,您使用捕获列表来处理对 self
的弱引用,并检查它是否尚未被释放
workItem = DispatchWorkItem { [weak self] in
guard let strongSelf = self else { return }
// do stuff with strongSelf
}
此函数应该重新安排工作项的执行:
class MyClass {
var id: String?
var workItem: DispatchWorkItem?
var isDoing = false
func myFunction() {
guard let id = self.id else { return }
isDoing = true
NotificationCenter.default.post(name: MyNotification, object: nil, userInfo: ["id": id])
workItem?.cancel()
workItem = DispatchWorkItem {
self.isDoing = false
NotificationCenter.default.post(name: MyNotification, object: nil, userInfo: ["id": id])
}
if let workItem = workItem {
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + DispatchTimeInterval.seconds(10), execute: workItem)
}
}
}
它在开发中工作正常,但设计似乎可疑,所以我问一些基本问题:
- 如果
workItem?.cancel()
在队列试图执行workItem
之前被调用,workItem
可能是零吗? - 当执行
workItem
时,workItem
中的id
是否可以为零,或者它是否被范围let id = self.id
保留? - 如果
MyClass
对象已被释放,那么在执行workItem
时,workItem
中的isDoing
是否已经被释放?换句话说,当MyClass
对象被释放时,调度的workItem
会发生什么?
不太清楚你的意思。你不会在任何地方取消
workItem
。不,它不能是
nil
,因为您正在使用局部变量 -self.id
的副本。通过使用guard
可以确保局部变量id
不为 nil,并且闭包保持对捕获值的强引用(默认情况下),因此它不会被释放。isDoing
是MyClass
的一个实例变量,所以它不能在MyClass
实例被释放之前被释放。问题是,在你的情况下MyClass
不能被释放,因为你正在寻找一个强大的参考周期。默认情况下,闭包保持对捕获值的强引用,并且您正在捕获self
。并且由于self
保持对workItem
的强引用,这反过来又保持对捕获self
的闭包的强引用,因此引用循环。
通常,当捕获 self
时,您使用捕获列表来处理对 self
的弱引用,并检查它是否尚未被释放
workItem = DispatchWorkItem { [weak self] in
guard let strongSelf = self else { return }
// do stuff with strongSelf
}