2

In my app , we have to make 3 server calls when we click on the login button.

1) will make a server call to get an OAuth token for user credentials
2) with the token from (1) we will get user privileges
3) with the token from (1) and with the valid privilege from (2) we will get the data to be displayed on the page after login in a tableview. 

I'm confused with the approach to take for this. Would it be a good approach to use operationqueue adding dependencies or to use NSURLSession tasks ?

According to one of the stack overflow solutions for this - Best practices for making a queue of NSURLSessionTasks , NSURLSession does not have any logic about ordering requests it will just call the completionBlock of whatever finishes first even when setting the maximum number of connections per host to 1

If there is any other better approach let me know..

Community
  • 1
  • 1
Sharanya K M
  • 1,805
  • 4
  • 23
  • 44

2 Answers2

1

you can use NSURLSession tasks. first call first api method and you will get response in completion handler(block). now store it in any public property (as you want to use it again) within completion handler. From that completion handler call second api method and from the completion handler of that second method, call third api method by passing response and using public property which have first api method's object stored.

Completion handler or blocks getting called only when response is arrived so by this way you can manage your api calls.

Hope this will help :)

Ketan Parmar
  • 27,092
  • 9
  • 50
  • 75
1

At the end of the day, a simplified version of your code utilising the traditional approach of "completion handlers" may look as follows:

fetchOAuthToken() { (token, error) in
    if let token = token {
        fetchPrivileges(token: token) { (privileges, error) in
            if let privileges = privileges {
               fetchData(token: token, privileges: privileges) { (data, error) in 
                   if let data = data {
                       // ... 
                   }
               }
            }
        }
    }
}

Note, that for brevity only, the code does not contain error handling and no means for cancellation.

The dependencies are established through the continuations - that is, the completion handlers.

Another approach utilising "Scala-like" futures will look as below (using Promises is quite similar approach):

fetchOAuthToken().flatMap { token in
    fetchPrivileges(token: token).flatMap { privileges in
        fetchData(token: token, privileges).map { data in
            // ...
        }
    }
}.onFailure { error in
    print("Error: \(error)")
}

The statement above creates one task which is composed out of three.

This approach contains full fledged error handling, even though it might not be obvious. The production version won't differ much than this snippet above - it may only add a means for cancellation.

There are a few third party libraries implementing Scala-like futures or Promises.

One approach adding cancellation, may look as follows:

let cr = CancellationRequest()
fetchOAuthToken(ct: cr.token).flatMap { token in
    fetchPrivileges(token: token, ct: cr.token).flatMap { privileges in
        fetchData(token: token, privileges, ct: cr.token).map { data in
            // ...
        }
    }
}.onFailure { error in
    print("Error: \(error)")
}

Later, you can cancel the composed task (what ever it is currently executing):

cr.cancel()

Note:

This problem can be solved with NSOperations, too. However, it would require three subclasses of NSOperation, and one or two thread-safe helper classes which will be used to "transfer" the result of Op1 to input of Op2, and the result of Op2 to the input of Op3. I would estimate that this will take about 500 lines of code -- too much for an answer on SO ;)

The "Scala-like" futures approach requires a third party library. The cancellation requires another - or your own implementation (which is not that difficult), or one library that provide all in one.

CouchDeveloper
  • 18,174
  • 3
  • 45
  • 67