This function is supposed to re-schedule the execution of a work item:
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)
}
}
}
It works fine in development, but the design seems suspicious, so I ask some basic questions:
- Could
workItem
be nil, ifworkItem?.cancel()
is called just before the queue tries to execute theworkItem
? - Could
id
insideworkItem
ever be nil whenworkItem
is executed or is it retained by the scopedlet id = self.id
? - Could
isDoing
insideworkItem
be already deallocated when theworkItem
is executed if theMyClass
object has been deallocated? In other words, what happens to the scheduledworkItem
when theMyClass
object is deallocated?
Not sure what you mean. You don't nil out
workItem
anywhere.No, it can't be
nil
since you're working with a local variable - a copy ofself.id
. By usingguard
you make sure that local variableid
is not nil, and closure keeps a strong reference (by default) to captured values, so it won't be deallocated.isDoing
is an instance variable ofMyClass
so it can't be deallocated beforeMyClass
instance is deallocated. The problem is, in your caseMyClass
can't be deallocated because you're looking at a strong reference cycle. The closure, by default, keeps a strong reference to the value captured, and you are capturingself
. And sinceself
keeps a strong reference toworkItem
, which in turn keeps a strong reference to closure that capturesself
, hence the reference cycle.In general, when capturing
self
you use a capture list to work with a weak reference toself
and do a check whether it hasn't been deallocated