I need to make an asynchronous call so that the second method is only called after the first one is completed.Both methods are network calls. Something like this:
signIn()
getContacts()
I want to make sure that getContacts only gets called after the signIn is completed. FWIW, I can't edit the methods signatures because they are from a Google SDK.
This is what I tried:
let queue = DispatchQueue(label: "com.app.queue")
queue.async {
signIn()
getContacts()
}
Async calls, by their nature, do not run to completion then call the next thing. They return immediately, before the task they were asked to complete has even been scheduled.
You need some method to make the second task wait for the first to complete.
NauralInOva gave one good solution: use a pair of NSOprations and make them depend on each other. You could also put the 2 operations into a serial queue and the second one wouldn't begin until the first is complete.
However, if those calls trigger an async operation on another thread, they may still return and the operation queue may trigger the second operation (the getContacts() call without waiting for signIn() to complete.
Another option is to set up the first function to take a callback:
signIn( callback: {
getContacts()
}
A third option is to design a login object that takes a delegate, and the login object would call a signInComplete method on the delegate once the signIn is complete.
This is such a common thing to do that most networking APIs are built for it "out out of the box." I'd be shocked if the Google API did not have some facility for handling this.
What Google framework are you using? Can you point to the documentation for it?
You're looking for NSOperation. You can use NSOperation to chain operations together using dependencies. Once one operation complete's it can pass it's completion block to the next operation. An example for your use case might be:
// AuthOperation is a subclass of NSOperation
let signInOperation = AuthOperation()
// ContactsOperation is a subclass of NSOperation
let getContactsOperation = ContactsOperation()
getContactsOperation.addDependency(signInOperation)
Ray Wenderlich has a great tutorial covering NSOperation. The tutorial uses a downloading operation to load images asynchronously with a dependency that will filter the photo upon completion of the network request.
There is also a great sample project by Apple that uses operations with asynchronous network requests.
Related
In iOS, we have GCD and Operation to handle concurrent programming.
looking into GCD we have QoS classes, and they're simple and straight forward, this question is about why DispatchQueue.main.async is commonly used to asynchronies X tasks in the Main Thread.
So when we usually handle updating something in the UI we usually use that function since to prevent any irresponsiveness from the application.
makes me think is writing code inside the UIViewController usually executed in the main thread ?
but also knowing that callback & completionHandler usually execute without specifying on what thread they are in, and the UI never had a problem with that !! so it is on the background ?
How Swift handles this ? and what thread am i writing on by default without specifying anything ?
Since there are more than one question here, let's attempt to answer them one by one.
why DispatchQueue.main.async is commonly used to asynchronies X tasks
in the Main Thread.
Before mentioning a direct answer, make sure that you don't have confusion of understanding:
Serial <===> Concurrent.
Sync <===> Async.
Keep in mind that DispatchQueue.main is serial queue. Using sync or async has nothing to do with determining serialization or currency of a queue, instead they refer to how the task is handled. Thus saying DispatchQueue.main.async means that:
returns control to the current queue right after task has been sent to
be performed on the different queue. It doesn't wait until the task is
finished. It doesn't block the queue.
cited from: https://stackoverflow.com/a/44324968/5501940 (I'd recommend to check it.)
In other words, async means: this will happen on the main thead and update it when it is finished. That's what makes what you said:
So when we usually handle updating something in the UI we usually use
that function since to prevent any irresponsiveness from the
application.
seems to be sensible; Using sync -instead of async- will block the main.
makes me think is writing code inside the UIViewController usually
executed in the main thread ?
First of all: By default, without specifying which thread should execute a chunk of code it would be the main thread. However your question seems to be unspecific because inside a UIViewController we can call functionalities that are not executed on the main thread by specifying it.
but also knowing that callback & completionHandler usually execute
without specifying on what thread they are in, and the UI never had a
problem with that !! so it is on the background ?
"knowing that callback & completionHandler usually execute without specifying on what thread they are in" No! You have to specify it. A good real example for it, actually that's how Main Thread Checker works.
I believe that there is something you are missing here, when dealing when a built-in method from the UIKit -for instance- that returns a completion handler, we can't see that it contains something like DispatchQueue.main.async when calling the completion handler; So, if you didn't execute the code inside its completion handler inside DispatchQueue.main.async so we should assume that it handles it for you! It doesn't mean that it is not implemented somewhere.
Another real-world example, Alamofire! When calling
Alamofire.request("https://httpbin.org/get").responseJSON { response in
// what is going on here work has to be async on the main thread
}
That's why you can call it without facing any "hanging" issue on the main thread; It doesn't mean its not handled, instead it means they handle it for you so you don't have to worry about it.
I am diving a bit deeper into concurrency and have been reading extensively about GCD and NSOperation. However, a lot of posts like the canonic answer on SO are several years old.
It seemed to me that NSOperation main advantages used to be, at the cost of some performance:
"the way to go" generally for more than a simple dispatch as the highest level abstraction (built atop of GCD)
to make task manipulation (cancellation, etc.) a lot easier
to easily set up dependencies between tasks
Given GCD's DispatchWorkItem & block cancellation / DispatchGroup / qos in particular, is there really an incentive (cost-performance wise) to use NSOperation anymore for concurrency apart from cases where you need to be able to cancel a task when it began executing or query the task state ?
Apple seems to put a lot more emphasis on GCD, at least in their WWDC (granted it's more recent than NSOperation).
I see them each still having their own purpose. I just recently rewatched the 2015 WWDC talk about this (Advanced NSOperations), and I see two main points here.
Run Time & User Interaction
From the talk:
NSOperations run for a little bit longer than you would expect a block to run, so blocks usually take a few nanoseconds, maybe at most a millisecond, to execute.
NSOperations, on the other hand, can be much longer, for anywhere from a couple of milliseconds to even several minutes
The example they talk about is in the WWDC app, where there exists an NSOperation that has a dependency on having a logged in user. The dependency NSOperation presents a login view controller and waits for the user to authenticate. Once finished, that NSOperation finishes and the NSOperationQueue resumes it's work. I don't think you'd want to use GCD for this scenario.
Subclassing
Since NSOperations are just classes, you can subclass them to get more reusability out of them. This isn't possible with GCD.
Example: (Using the WWDC login scenario from above)
You have many NSOperations in your code base that are associated with a user interaction that requires them to be authenticated. (Liking a video, in this example.) You could extend NSOperation to create an AuthenticatedOperation, then have all those NSOperations extend this new class.
First off, NSOperationQueue let you enqueue operations, that is, some sort of asynchronous operations with a start method, a cancel method and a few observable properties, while with a dispatch queue one can submit a block or a closure or a function to a dispatch queue, which will be then executed.
An "Operation" is semantically fundamentally different than a block (or closure, function). An operation has an underlying asynchronous task, while a block (closure or functions) is just that.
What comes close to an NSOperation, though, is an asynchronous function, e.g.:
func asyncTask(param: Param, completion: (T?, Error?) ->())
Now with Futures we can define the same asynchronous function like:
func asyncTask(param: Param) -> Future<T>
which makes such asynchronous functions quite handy.
Since futures have combinator functions like map and flatMap and so on, we can quite easily "emulate" the "dependency" feature of NSOperation, just in a more powerful, more concise and more comprehensible way.
We can also implement some sort of NSOperationQueue with a few lines of code based solely on GCD, say a "TaskQueue" and with basically the same features, like "maxConcurrentTasks" and can use it to enqueue task functions (not operations), in just a more powerful, more concise and a more comprehensible way as well. ;)
In order to get a cancelable operation, you need to create a subclass of NSOperation - while you can create a async function "ad-hod" - inline.
Also, since cancellation is an independent concept, we can assume, that there exists some library whose implementation is solely based on GCD which solves this problem in the, uhm, the usual way ;) It may look like this:
self.cancellationRequest = CancellationRequest()
self.asyncTask(param: param, cancellationToken: cr.token).map { result in
...
}
and later:
override func viewWillDisappear(_ animated: animated) {
super.viewWillDisappear(animated)
self.cancellationRequest.cancel()
}
So, IMHO there's really no reason to use clunky NSOperation and NSOperationQueue, and there's no reason any more for subclassing NSOperation, which is quite elaborate and surprising difficult, unless you don't care about data races.
I call a network task to fetch some JSON when user selects a cell in a UICollectionView. This is asynchronous so the UI remains active whilst the data is being retrieved. Allowing user to select another cell in the UICollectionView. I do not want to stop this but I do want a way to cancel the first function call and call the new method for the now selected cell.
Is there a way to in perhaps didDeselectItemAt indexPath: to cancel any currently executing tasks?
I was thinking to place a "please wait" modal view over the UI which would prevent a second cell selection until the function returned. Is this my best option or is there a better way?
You can use a NSOperationQueue to create and keep track of the asyncronous requests and cancel them when necessary.
See the answers to this other question here:
GCD cancel async block?
By maintaining separate threads using NSOperationQueue enables controls over tasks in the middle of execution whereas GCD wont allow the same but both works for background and foreground execution of particular task mechanism.
GCD is a lightweight way to represent units of work that are going to be executed concurrently. You don’t schedule these units of work; the system takes care of scheduling for you.
NSOperation adds a little extra overhead compared to GCD, but you can add dependency among various operations and re-use, cancel or suspend them.
Sample:
var backgroundQueue = NSOperationQueue()
backgroundQueue.addOperationWithBlock(){
println("hello from background")
NSOperationQueue.mainQueue().addOperationWithBlock(){
self.theLabel.text = "updated from main thread"
}
}
Now can do various operation provided NSOperationQueue over backgroundQueue variable.
You can submit your networking tasks as NSOperations to an NSOperationQueue.
NSOperation has a cancel method, and NSOperationQueue has a cancelAllOperations method.
I realize this question sounds contradictory. I have several Async requests going out in an application. The situation is that the first async request is an authentication request, and the rest will use an access token returned by the successful authentication request.
The two obvious solutions would be:
run them all synchronous, and risk UI block. (bad choice)
run them async, and put request 2-N in the completion handler for the first one. (not practical)
The trouble is that the subsequent requests may be handled anywhere in the project, at anytime. The failure case would be if the 2nd request was called immediately after the 1st authentication request was issued, and before the access token was returned.
My question thus is, is there any way to queue up Async requests, or somehow say not to issue them until the first request returns successfully?
EDIT:
Why (2) is not practical: The first is an authentication request, happening when the app loads. The 2nd+ may occur right away, in which case it is practical, but it also may occur in a completely separate class or any other part of a large application. I can't essentially put the entire application in the completion handler. Other accesses to the API requests may occur in other classes, and at anytime. Even 1-2 days away after many other things have occurred.
SOLUTION:
//pseudo code using semaphore lock on authentication call to block all other calls until it is received
// at start of auth
_semaphore = dispatch_semaphore_create(0)
// at start of api calls
if(_accessToken == nil && ![_apiCall isEqualToString:#"auth]){
dispatch_semaphore_wait(_semaphore, DISPATCH_TIME_FOREVER);
}
// at end of auth with auth token
dispatch_semaphore_signal([[SFApi Instance] semaphore]);
_accessToken = ...;
This sounds like a case where you'd want to use NSOperation's dependencies
From apple docs:
Operation Dependencies
Dependencies are a convenient way to execute operations in a specific order. You can add and remove dependencies for an operation using the addDependency: and removeDependency: methods. By default, an operation object that has dependencies is not considered ready until all of its dependent operation objects have finished executing. Once the last dependent operation finishes, however, the operation object becomes ready and able to execute.
note that in order for this to work, you must subclass NSOperation "properly" with respect to KVO-compliance
The NSOperation class is key-value coding (KVC) and key-value observing (KVO) compliant for several of its properties. As needed, you can observe these properties to control other parts of your application.
You can't really have it both ways-- there's no built-in serialization for the NSURLConnection stuff. However, you are probably already funneling all of your API requests through some common class anyway (presumably you're not making raw network calls willy-nilly all over the app).
You'll need to build the infrastructure inside that class that prevents the execution of the later requests until the first request has completed. This suggests some sort of serial dispatch queue that all requests (including the initial auth step) are funneled through. You could do this via dependent NSOperations, as is suggested elsewhere, but it doesn't need to be that explicit. Wrapping the requests in a common set of entry points will allow you to do this any way you want behind the scenes.
In cases like this I always find it easiest to write the code synchronously and get it running on the UI thread first, correctly, just for debugging. Then, move the operations to separate threads and make sure you handle concurrency.
In this case the perfect mechanism for concurrency is a semaphore; the authentication operation clears the semaphore when it is done, and all the other operations are blocking on it. Once authentication is done, floodgates are open.
The relevant functions are dispatch_semaphore_create() and dispatch_semaphore_wait() from the Grand Central Dispatch documentation: https://developer.apple.com/library/ios/documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html#//apple_ref/doc/uid/TP40008079-CH2-SW2
Another excellent solution is to create a queue with a barrier:
A dispatch barrier allows you to create a synchronization point within a concurrent dispatch queue. When it encounters a barrier, a concurrent queue delays the execution of the barrier block (or any further blocks) until all blocks submitted before the barrier finish executing. At that point, the barrier block executes by itself. Upon completion, the queue resumes its normal execution behavior.
Looks like you got it running with a semaphore, nicely done!
Use blocks... 2 ways that I do it:
First, a block inside of a block...
[myCommKit getPlayerInfoWithCallback:^(ReturnCode returnCode, NSDictionary *playerInfo) {
if (playerInfo) {
// this won't run until the first one has finished
[myCommKit adjustSomething: thingToAdjust withCallback:^(ReturnCode returnCode, NSDictionary *successCode) {
if (successCode) {
// this won't run until both the first and then the second one finished
}
}];
}
}];
// don't be confused.. anything down here will run instantly!!!!
Second way is a method inside of a block
[myCommKit getPlayerInfoWithCallback:^(ReturnCode returnCode, NSDictionary *playerInfo) {
if (playerInfo) {
[self doNextThingAlsoUsingBlocks];
}
}];
Either way, any time I do async communication with my server I use blocks. You have to think differently when writing code that communicates with a server. You have to force things to go in the order you want and wait for the return success/fail before doing the next thing. And getting used to blocks is the right way to think about it. It could be 15 seconds between when you start the block and when it gets to the callback and executes the code inside. It could never come back if they're not online or there's a server outage.
Bonus way.. I've also sometimes done things using stages:
switch (serverCommunicationStage) {
case FIRST_STAGE:
{
serverCommunicationStage = FIRST_STAGE_WAITING;
// either have a block in here or call a method that has a block
[ block {
// in call back of this async call
serverCommunicationStage = SECOND_STAGE;
}];
break;
}
case FIRST_STAGE_WAITING:
{
// this just waits for the first step to complete
break;
}
case SECOND_STAGE:
{
// either have a block in here or call a method that has a block
break;
}
}
Then in your draw loop or somewhere keep calling this method. Or set up a timer to call it every 2 seconds or whatever makes sense for your application. Just make sure to manage the stages properly. You don't want to accidentally keep calling the request over and over. So make sure to set the stage to waiting before you enter the block for the server call.
I know this might seem like an older school method. But it works fine.
I have simple class for perform network stuff. It's a singleton and it encapsulates NSOperationQueue inside it. When class' user calls some method to getting data from network, this class creates proper instance of operation class inherited from NSOperation sets up it and adds to queue for performing. Obviously, that performing is making asynchronously in separated threads. After getting data from network NSOperation inherited object notifies my network class and it notifies interested delegates about data getting finished or error.
Question is, how can I make unit tests for checking network class' logic? Also, I don't actually want to test server side behavior. I just want to replace actual async call to server with mock and predefined answers to after test handlers' behavior. I want to check how are my classes work, not server side. I understand commonly logic for testing stuff like that but I little bit confused with using OCMock for it.
Best answer will be code example. I'm using OCUnit and OCMock in my project for unit testing.
Also any articles or github links will be perfect.
If all the asynchronous calls go through an internal method in your class, you can simply create a partial mock on your object and use stub/expect on that method. You can then call the public methods as normal and use the mock to verify that the internal method is called. Using the partial mock stops the real implementation from being called, so no network activity should occur.
As to the other half, the call-backs from the asynchronous operation, simply call the method that would be called directly from your tests, then check that your class does the right thing, either by checking its state with OCUnit asserts, or, if it in turn uses callbacks, with another mock.
So I know this is regarding OCMock... but I thought I'd put it out there that I do this successfully with Kiwi and it looks like this.
it(#"should refresh the client's temporary API key if it is stale before sending the request", ^{
ISLDataServiceAdd *addRequest = [ISLDataServiceAdd withRecord:#{ISLFieldContact_FirstName: #"Jason"} table:ISLTableContact];
[[clientMock shouldEventually] receive:#selector(apiKey) andReturn:VALID_API_KEY];
[[clientMock shouldEventually] receive:#selector(hasTemporaryAPIKey) andReturn:theValue(YES)];
[[clientMock shouldEventually] receive:#selector(isTemporaryAPIKeyStale) andReturn:theValue(YES)];
[[clientMock shouldEventually] receive:#selector(refreshTemporaryAPIKeyAndWait:)];
[addRequest sendRequestUsingClient:clientMock completion:nil failure:nil];
});
sendRequestUsingClient:completion:failure: is an asynchronous call, so by using shouldEventually with Kiwi, it knows that it needs to wait some time (default is 1 second) before those selectors will be called.