Reputation: 67
I don't want this to be misconstrued as a duplicate. I want to deal with callback hell arising from API calls from Firestore (database by Firebase, a Google platform). I can't modify their function declarations, so I assume I will have to wrap their functions with some of my code.
For example, in the code below, the function eventCreatedSuccessfully()
can only be called after the asynchronous function completes. eventCreatedSuccessfully()
also contains a function call to firebase that has a closure, which another function relies on and etc...Though this isn't causing me problems right now, it probably will as my App grows larger and larger. I researched online and found solutions like Futures and Streams from third-party frameworks, but I didn't know how to integrate them into code I have no control over (the API calls).
batch.commit { (error) in
self.dismiss(animated: true) {
if error == nil {
self.eventCreatedSuccessfully()
print("Event created successfully")
} else {
print(error!.localizedDescription)
}
}
}
Upvotes: 2
Views: 1897
Reputation: 6018
I researched online and found solutions like Futures and Streams (...)
In most cases futures and streams is all about PromiseKit
and RxSwift
frameworks.
If you have only big amount of closures try to use PMK. It's very simple and easy to use. PMK also has nice documentation section on github.
RxSwift is more advanced level, because it requires you to write code fully to paradigm of itself - starts from server/firebase request and ends with ui. Also, there is a good note at PMK github about difference of these two.
Also, should be note, that google also has nice library called promises
. According to their benchmarks google's library is leader in almost all nominations.
Upvotes: 0
Reputation: 7552
Wrap the calls in promises. Any of the popular libraries will do the trick. The one that comes to mind is PromiseKit, available (at the time of this writing) at https://github.com/mxcl/PromiseKit.
Here is code I wrote for a work project (it's open source) which wraps a function that takes a completion, and returns a Promise which will signal with the result when the completion is called. It's using an internal Promise implementation, but the process can be adapted to other implementations.
public func promise<Return>(_ task: (@escaping (Return?, Error?) -> ()) -> ()) -> Promise<Return> {
let p = Promise<Return>()
task { (value: Return?, error: Error?) -> Void in
if let error = error {
p.signal(error)
}
if let value = value {
p.signal(value)
}
}
return p
}
The completion is expected to be called with a result of some kind, or an error. Adapt as required for your use-case.
An example usage follows.
public typealias BalanceCompletion = (Balance?, Error?) -> Void
func balance(completion: @escaping BalanceCompletion) {
guard deleted == false else {
completion(nil, KinError.accountDeleted)
return
}
Stellar.balance(account: stellarAccount.publicKey!, asset: asset, node: node)
.then { balance -> Void in
completion(balance, nil)
}
.error { error in
completion(nil, KinError.balanceQueryFailed(error))
}
}
func balance() -> Promise<Balance> {
return promise(balance)
}
Upvotes: 1