Here's an example of the code this question is about:
func executeTask() {
fetchApiData().then { foos in
return filterData(foos)
}.then { foos in
return saveData(foos)
}.catch {
/** handle error **/
}
}
func fetchApiData() -> Promise<[Foo]> {
return Promise<[Foo]> { fulfil, reject in
/* Do a network request, and run through object mapper */
fulfil( myFooCollection )
}
}
func filterData(_ data: [Foo]) -> Promise<[Foo]> {
return Promise<[Foo]> { fulfil, _ in
_ = getIdsToFilter().then { ids -> Void in
let filteredData = data.filter { foo in
return ids.contains(foo.id)
}
fulfil(filteredData)
}
}
}
func getIdsToFilter() -> Promise<[Int]> {
return Promise<[Int]> { fulfil, _ in
/* Do some task here */
fulfil([10,20,30,40])
}
}
func saveData(_ data: [Foo]) -> Promise<[Foo]> {
return Promise<[Foo]> { fulfil, reject in
/* Do some save task here */
fulfil(data)
}
}
The function in particular I'm querying is the filterData
one.
This is a pretty simple promise chain, get some data, filter it, then save it. However the filtering process requires the response from another promise before it can do it's thing.
As you can see, i've implemented this as a type of wrapper. I return the promise I need, but that promise calls another one from within itself, before doing it's thing.
I feel like this is a bit ugly and goes against the whole composition idea of Promises. I'm thinking there should be a way of doing something like this instead:
func filterData(_ data: [Foo]) -> Promise<[Foo]> {
return getIdsToFilter().then { ids in
return data.filter { foo in
return ids.contains(foo.id)
}
}
}
However that of course doesn't work as xcode says:
Cannot convert return expression of type '[Foo]' to return type 'Promise<[Foo]>' (aka 'Promise<Array<Foo>>')
So... is there a way of flattening out that function? Or maybe what i'm doing is correct and that's how it should be?
P.S: I'm not looking for some overly complex, over-engineered solution to flattening that out. I'm just trying to follow some sort of best practice, being nested isn't the problem, I just want to be doing things "properly"
Function func filterData(_ data: [Foo]) -> Promise<[Foo]>
expects to return promise.
In you case the expression
data.filter { foo in
return ids.contains(foo.id)
}
returns Array
of Foo
objects. You have to wrap [Foo]
to Promise object. See the example below
func filterData(_ data: [Foo]) -> Promise<[Foo]> {
return Promise { _ in
return getIdsToFilter().then { ids in
return Promise(value: data.filter { return ids.contains($0.id) })
}
}
}
Update: To understand what is wrong you can explicit declare the type of return parameters. Then you will see what type expects swift compiler and what type expect you. This tactic helps me understand compiler errors
func filterData(_ data: [Foo]) -> Promise<[Foo]> {
return Promise { _ in
return getIdsToFilter().then { ids -> Promise<[Foo]> in
return Promise(value: data.filter { return ids.contains($0.id) })
}
}
}