Chaining multiple async functions in Swift

2019-07-20 10:01发布

问题:

I'm trying to write a series of functions that will validate the user's information before asking them to confirm something. (Imagine a shopping app).

  1. I first have to check that the user has added a card.
  2. Then I have to check that they have sufficient balance.
  3. Then I can ask them to confirm the payment.

I can write the async method to check the card something like ...

func checkHasCard(completion: (Bool) -> ()) {
    // go to the inter webs
    // get the card
    // process data
    let hasCard: Bool = // the user has a card or not.
    completion(hasCard)
}

This can be run like this...

checkHasCard {
    hasCard in
    if hasCard {
        print("YAY!")
    } else {
        print("BOO!")
    }
}

But... now, based off that I have to do various things. If the user does have a card I then need to continue onwards and check there is sufficient balance (in much the same way). If the user does not have a card I present a screen for them to add their card.

But it gets messy...

checkHasCard {
    hasCard in
    if hasCard {
        // check balance
        print("YAY!")
        checkBalance {
            hasBalance in
            if hasBalance {
                // WHAT IS GOING ON?!
                print("")
            } else {
                // ask to top up the account
                print("BOO!")
            }
        }
    } else {
        // ask for card details
        print("BOO!")
    }
}

What I'd like instead is something along the lines of this...

checkHasCard() // if no card then show card details screen
    .checkBalance() // only run if there is a card ... if no balance ask for top up
    .confirmPayment()

This looks much more "swifty" but I'm not sure how to get closer to something like this.

Is there a way?

回答1:

Asynchronous operations, ordered and with dependencies? You're describing NSOperation.

Certainly you can chain tasks using GCD:

DispatchQueue.main.async {
    // do something
    // check something...
    // and then:
    DispatchQueue.main.async {
        // receive info from higher closure
        // and so on
    }
}

But if your operations are complex, e.g. they have delegates, that architecture completely breaks down. NSOperation allows complex operations to be encapsulated in just the way you're after.