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 workItembe nil, ifworkItem?.cancel()is called just before the queue tries to execute theworkItem?
- Could idinsideworkItemever be nil whenworkItemis executed or is it retained by the scopedlet id = self.id?
- Could isDoinginsideworkItembe already deallocated when theworkItemis executed if theMyClassobject has been deallocated? In other words, what happens to the scheduledworkItemwhen theMyClassobject is deallocated?
 
                        
Not sure what you mean. You don't nil out
workItemanywhere.No, it can't be
nilsince you're working with a local variable - a copy ofself.id. By usingguardyou make sure that local variableidis not nil, and closure keeps a strong reference (by default) to captured values, so it won't be deallocated.isDoingis an instance variable ofMyClassso it can't be deallocated beforeMyClassinstance is deallocated. The problem is, in your caseMyClasscan'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 sinceselfkeeps a strong reference toworkItem, which in turn keeps a strong reference to closure that capturesself, hence the reference cycle.In general, when capturing
selfyou use a capture list to work with a weak reference toselfand do a check whether it hasn't been deallocated