I known, this is an old question, but interestingly enough, and there is a nice solution:
Suppose, all those functions were asynchronous. The asynchronous pattern is called a "Continuation".
A possible implementation of such a "continuation" could use dispatch queues and blocks directly, for example:
dispatch(my_queue, ^{
[self connectDeviceWithCompletion:^(id result){
if (result) {
[self authenticateWithCompletion:^(id result){
if (result) {
[self performTwoFactorAuthWithCompletion:^(id result) {
if (result) {
...
}
}];
}
}];
}
}];
});
As you can see, "continuation" with dispatch and blocks becomes quickly confusing, and I didn't even add error checking, and cancellation.
Note, that canceling a block which has been enqueued isn't that easily possible.
A more comprehensible solution that also supports error handling and cancellation can be achieved using a concept called "Promise" (see wiki Futures and promises]. Promises are very popular in JavaScript and other languages, but there are a few Objective-C libraries which implement Promises, see this answer:
success:/failure: blocks vs completion: block.
Utilizing the RXPromise library one could write:
RXPromise* finalResult = [self connectDevice]
.then(^(id result){
// device successfully connected with result
return [self authenticate];
}, nil)
.then(^id(id result){
// authenticated successfully with result
return [self performTwoFactorAuth];
}, nil)
.then(^id(id result){
// successfully performed two-factor-authentication
// do something
...
}, nil)
[finalResult setTimeout:5*60]; // we cancel everything after 5 minutes
// Catch any error:
finalResult.then(nil, id(NSError* error){
NSLog(@"Something went wrong, or user cancelled with error: %@", error);
});
self.finalResultPromise = finalResult;
...
Later:
Suppose, the user waits for an result to happen eventually. When navigating back from the current view, this shall cancel all the asynchronous operations:
- (void) viewDidDisappear:(BOOL)animated {
// we are no longer interested in the result
[self.finalResultPromise cancel];
self.finalResultPromise = nil;
[super viewDidDisappear:animated];
}
Disclosure: I'm the author of RXPromsie ;)