4

Let's say that I want to generate a data set that requires multiple promises to resolve, how would I store each result down the promise chain so I can create my final data set in one shot?

struct CompleteData {
    let a: String
    let b: String
}

func getData() -> Promise<CompleteData> {
    getA().then { a -> Promise<String> in
        return a.getB()
    }.then { b -> CompleteData in
        return CompleteData(a: ???, b: b)
    }
}

The solutions that I'm coming up with don't feel elegant enough:

Temporary IUOs

Use implicitly-unwrapped optionals to store temporary values. This can break if I forget to assign to a.

func getData() -> Promise<CompleteData> {
    var a: String!
    getA().then { _a -> Promise<String> in
        _a = a
        return _a.getB()
    }.then { b -> CompleteData in
        return CompleteData(a: a, b: b)
    }
}

Nested promises

Nest promises and access values from the outer scopes. This defeats the purpose of promises by getting into a nesting hell.

func getData() -> Promise<CompleteData> {
    getA().then { a -> Promise<CompleteData> in
        return a.getB().then { b -> CompleteData in
            return CompleteData(a: a, b: b)
        }
    }
}

Other solutions on top of my head: use optional fields in CompleteData, use var fields in CompleteData and assign as the chain resolves, none of those are good to me.

Can someone think of a more elegant way to do this?

ldiqual
  • 15,015
  • 6
  • 52
  • 90

1 Answers1

7

You could use tuples to pass data down the promise chain. You just need to specify tuple and "a" return promise. Use .map to return tuple. Here is the code on your example:

struct CompleteData {
    let a: String
    let b: String
}

func getData() -> Promise<CompleteData> {
    getA().then { a -> Promise<(String, a)> in
        return a.getB().map{ ($0, a) }
        }.then { (b, a) -> CompleteData in
            return CompleteData(a: a, b: b)
    }
}

PromiseKit documentation

Hope it will help you. Cheers :)

Hamed
  • 1,678
  • 18
  • 30