Reputation: 4107
In my app I have a method that makes cloud calls. It has a completion handler. At some point I have a situation when a users makes this call to the cloud and while waiting for the completion, the user might hit log out.
This will remove the controller from the stack, so the completion block will be returned to the controller that is no longer on a stack.
This causes a crash since I do some UI tasks on that completion return. I did a workaround where, I'm not doing anything with the UI is the controller in no longer on a stack.
However, I'm curious if it's possible to cancel/stop all pending callbacks somehow on logout?
Upvotes: 2
Views: 1703
Reputation: 5694
For the granular control over operations' cancellation, you can return a cancellation token out from your function. Call it upon a need to cancel an operation.
Here is an example how it can be achieved:
typealias CancellationToken = () -> Void
func performWithDelay(callback: @escaping () -> Void) -> CancellationToken {
var cancelled = false
// For the sake of example delayed async execution
// used to emulate callback behavior.
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
if !cancelled {
callback()
}
}
return { cancelled = true }
}
let cancellationToken = performWithDelay {
print("test")
}
cancellationToken()
For the cases where you just need to ensure that within a block execution there are still all necessary prerequisites and conditions met you can use guard
:
{ [weak self] in
guard let `self` = self else { return }
// Your code here... You can write a code down there
// without worrying about unwrapping self or
// creating retain cycles.
}
Upvotes: 1
Reputation: 36317
I'm not sure, but I think something is tightly coupled. Try doing:
{ [weak self] () -> Void in
guard let _ = self else { return }
//rest of your code
}
If you get deinitialized then your completioHanlder would just not proceed.
Upvotes: 3