BFTask
has been good to me but I have one complaint: I've yet to see a working example of how you ought to cancel
a task. The entirety of the documentation on the subject is found on their GitHub page with a single lowly section that includes everything but the part I care about: how to cancel the task.
// Somewhere else.
MYCancellationToken *cancellationToken = [[MYCancellationToken alloc] init];
[obj doSomethingComplicatedAsync:cancellationToken];
// When you get bored...
[cancellationToken cancel];
Their code snippet is followed by:
Note: The cancellation token implementation should be thread-safe.
I am wondering the following:
cancel
method on the BFTask
interface itself? They have a property representing whether the task was canceled but no means to cancel it.cancellationToken(s)
property on the BFTask
itself?cancel
strongly coupled to the task itself? Or is a general implementation possible as in the case of cancelAllOperations
of an NSOperationQueue
?BFTask
is an implementation of the Future and Promises construct:BFTask
is a Future
: it is a read-only placeholder view of a variable.BFTaskCompletionSource
is a promise: it is a writable, single assignment container which sets the value of the future. (or an error - or cancels the task)BFTask
public interface remains read-only , hence it does not allow you to cancel it directly.BFCancellationToken
token just stores a state, which the BFTask
can check. Your async task code can basically regularly check cancellationRequested
is set to true, which allows you to manually cancel your task.
There is a fairly useful implementation of cancellation tokens in Bolts, but for some reason it isn't documented at all outside of the header files. The key is the usage of the BFCancellationTokenSource
. You need to keep a reference to the BFCancellationTokenSource
in order to issue and cancel a BFCancellationToken
.
In my example I have a particular function called cancellableFunction()
that issues a bunch of tasks in succession. If the function is called again before the last call has completed, I want uncompleted tasks of the previous call to be cancelled.
The key here is to pass the token
into each continueWith
function call. If at any time the token
is cancelled via the tokenSource
, unreached successBlock
s won't be executed. You can also check the status of cancellation via task.cancelled
in each BFContinuationBlock
(obviously will be false in success blocks).
Here is an example:
class ViewController: UIViewController {
...
// instance reference to tokenSource so that it can be cancelled by any function in the ViewController
var tokenSource: BFCancellationTokenSource?
...
func cancellableFunction() -> BFTask {
// First cancel the previous token
tokenSource?.cancel()
// Replace the previous TokenSource with a new one
tokenSource = BFCancellationTokenSource()
// Issue new Token from the new TokenSource
let token = tokenSource!.token
return functionThatReturnsBFTask().continueWithSuccessBlock({ (task:BFTask) -> AnyObject? in
...
return nil
}, cancellationToken: token).continueWithExecutor(BFExecutor.mainThreadExecutor(), successBlock: { (task:BFTask) -> AnyObject? in
...
return nil
}, cancellationToken: token).continueWithBlock({ (task:BFTask) -> AnyObject? in
// Here you can perform an actions you want to take on cancellation
if task.cancelled {
}
...
return nil
}, cancellationToken: token)
}
...
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With