Sequential Network Requests in Swift 3

914 views Asked by At

I have multiple network requests that need to happen in sequential order. They must wait until the previous has finished and received its response from the server.

Right now I have a callback pyramid of death. Is there a more automated way of doing this? I tried an OperationQueue but it doesn't wait for the requests to finish before advancing to the next request even with it set to do one request at a time.

For what it's worth, .save is a network request to CloudKit. There is no CloudKit subscription queue like there is with other CloudKit operations.

self.privateDB.save(subscriptions[0]){ savedSubscription, error in
  //Request 1 is done
  self.privateDB.save(subscriptions[1]){ savedSubscription, error in
    //Request 2 is done
    self.privateDB.save(subscriptions[2]){ savedSubscription, error in
      //All 3 requests are done
    }
  }
}

I tried a DispatchGroup but this doesn't seem to work. All the requests seem to fire before waiting for a response.

let group = DispatchGroup()

//Create a subscription for every record type
for subscription in subscriptions{
  group.enter()
  //...
  self.privateDB.save(subscription){ savedSubscription, error in
    group.leave()
  }    
}
group.wait()

Any ideas?

2

There are 2 answers

1
Andrew Madsen On BEST ANSWER

You should be able to create one or more CKModifySubscriptionsOperation to save the subscriptions, then use CKDatabase.add() to run them. If you need them to run in order, set up dependencies between them to ensure they run in order:

let subscriptionOp1 = CKModifySubscriptionsOperation(subscriptionsToSave: subscriptions[0], subscriptionsToDelete: nil)
let subscriptionOp2 = CKModifySubscriptionsOperation(subscriptionsToSave: subscriptions[1], subscriptionsToDelete: nil)
let subscriptionOp3 = CKModifySubscriptionsOperation(subscriptionsToSave: subscriptions[2], subscriptionsToDelete: nil)

subscriptionOp2.addDependency(subscriptionOp1)
subscriptionOp3.addDependency(subscriptionOp2)

database.add(subscriptionOp1)
database.add(subscriptionOp2)
database.add(subscriptionOp3)
0
SP74 On

Try to use semaphore to make them in sync.

  1. Create semaphore

    var semaphore = dispatch_semaphore_create(0)

  2. wait for completion of 1st api call

    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)

  3. Signal the semaphore in 1st api completion.

    dispatch_semaphore_signal(semaphore)

Ex :

var semaphore = dispatch_semaphore_create(0) self.privateDB.save(subscriptions[0]){ savedSubscription, error in dispatch_semaphore_signal(semaphore) } dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER) self.privateDB.save(subscriptions[1]){ savedSubscription, error in}