At the end of the day, a simplified version of your code utilising the traditional approach of "completion handlers" may look as follows:
fetchOAuthToken() { (token, error) in
if let token = token {
fetchPrivileges(token: token) { (privileges, error) in
if let privileges = privileges {
fetchData(token: token, privileges: privileges) { (data, error) in
if let data = data {
// ...
}
}
}
}
}
}
Note, that for brevity only, the code does not contain error handling and no means for cancellation.
The dependencies are established through the continuations - that is, the completion handlers.
Another approach utilising "Scala-like" futures will look as below (using Promises is quite similar approach):
fetchOAuthToken().flatMap { token in
fetchPrivileges(token: token).flatMap { privileges in
fetchData(token: token, privileges).map { data in
// ...
}
}
}.onFailure { error in
print("Error: \(error)")
}
The statement above creates one task which is composed out of three.
This approach contains full fledged error handling, even though it might not be obvious. The production version won't differ much than this snippet above - it may only add a means for cancellation.
There are a few third party libraries implementing Scala-like futures or Promises.
One approach adding cancellation, may look as follows:
let cr = CancellationRequest()
fetchOAuthToken(ct: cr.token).flatMap { token in
fetchPrivileges(token: token, ct: cr.token).flatMap { privileges in
fetchData(token: token, privileges, ct: cr.token).map { data in
// ...
}
}
}.onFailure { error in
print("Error: \(error)")
}
Later, you can cancel the composed task (what ever it is currently executing):
cr.cancel()
Note:
This problem can be solved with NSOperations
, too. However, it would require three subclasses of NSOperation
, and one or two thread-safe helper classes which will be used to "transfer" the result of Op1 to input of Op2, and the result of Op2 to the input of Op3. I would estimate that this will take about 500 lines of code -- too much for an answer on SO ;)
The "Scala-like" futures approach requires a third party library. The cancellation requires another - or your own implementation (which is not that difficult), or one library that provide all in one.