I use AFNetworking as my connection lib to my app. Due to the back-end restrictions, I cannot send two request simultaneously when the app starts because the server will identify a CookieTheftException (Grails). After a first successful connection, I can do as many simultaneous requests as I want but the first need to be serial.
How can I achieve that?
I thought using a Semaphore but i can't block the main thread.
Edit 1
I tried to override but it didn't work. I think the operation queue doesn't wait one request to finish (including it's callback) to start the other.
- (void)enqueueHTTPRequestOperation:(AFHTTPRequestOperation *)operation
{
[self.operationQueue setMaxConcurrentOperationCount:1];
[super enqueueHTTPRequestOperation:operation];
}
Edit 2
I realized that the maxConcurrentOperation worked and in fact 1 operation is executed at a time. The problem is that the request enqueued is already created without the cookies the server needs.
I don't know anything about Grails or the specific architecture of your system, but perhaps this could be solved by simply turning off cookies on that request, with NSMutableURLRequest -setHTTPShouldHandleCookies:.
Other than that, the best way to ensure that only one request operation is ever running for that initial call would be to ignore queues altogether, and simply have an AFHTTPRequestOperation property on your AFHTTPClient subclass. You could even get fancy with KVO to ensure that the operation queue is suspended until that initial request is finished.
I would recommend to read about GCD
You can create a queue and put some block to be executed in this queue.
This way:
It won't block main thread
Since all your networking blocks will be executed in one queue, there is no way that two blocks will be executed simultaneously.
You could set the maximum concurrent operations of the queue to 1. That way only one request will be made at a time.
[self.httpClient.operationQueue setMaxConcurrentOperationCount:1];
But since you only need to wait for the first request, why not just call that request on its own, then initialize the other requests only when the first one completed?
Related
I need to execute synchronous requests on API using Swift. Requests must be queued. Meaning, if one is already in progress and it awaits response it must not be canceled or interrupted by the next synchronous request that enters queue or is already in queue.
Requests must be executed in order as they enter queue (FIFO). Next request must not start until previous is finished/completed in the queue.
Also, every single request in queue must be executed until queue is empty. Synchronous requests can enter queue at any time.
I meant to implement a Synchronous API Client as a singleton which contains its own Queue for queued requests. Requests must not stop/freeze UI. UI has to be responsive on user interaction all the time.
I know it can be done with semaphores but, unless you know what your are doing and you are completely sure how semaphores work, it is not the safest or maybe the best way do it. Otherwise, potential bugs and crashes could appear.
I'm expecting successful execution of every synchronous request that enters queue (by FIFO order, regardless if it returns success or an error as a response) and UI updates immediately after.
So, my question is what is the best way to approach and solve this problem?
Thanks for your help and time.
You can create your own DispatchQueue and put you operations on it as DispatchWorkItems. It is serial per default. Just remember to call your completions on DispatchQueue.main if you plan to update the UI.
John Sundell has a wonderful article about DispatchQueues here:
https://www.swiftbysundell.com/articles/a-deep-dive-into-grand-central-dispatch-in-swift/
An app I am working on requires creating a container object on a server and inserting items into that container. I don't want to create the container object until the first item needs to be inserted. However, creating the container object requires some initialization that may take a little time. While that container is still initializing the user can still to send insertion requests that aren't getting handled because the container isn't ready yet. I have two main questions:
Should this be dealt with on the client or server side?
What is the best practice for dealing with kind of this issue?
Essentially, I need to ensure my initial createContainer data task in complete before any insertItem requests are sent.
Addition Information
An insertItem request is sent by clicking on a corresponding tableViewCell. The first tableViewCell a user clicks on sends a createContainer request that creates a container holding the first item.
For a container holding n items, the request should be sent in the following order:
createContainer(Container(with: item1)
insertItem(item2)
...
insertItem(itemn)
After the first request completes, the remaining n – 1 requests may complete in any order.
My Thoughts
It sounds like I want the createContainer request to be handled synchronously while the insertItem request should be handled asynchronously. I'm not sure if that is the best approach or even how to perform that appropriately, so any guidance would be greatly appreciated.
You can use a NSOperationQueue and multiple NSOperations to implement your desired behavior. A NSOperation instance can be dependent on the completion of another NSOperation instance:
dependencies
An array of the operation objects that must finish
executing before the current object can begin executing.
For your example this would mean that the insertItem-Operations are dependent on the createContainer operation.
When you add all those operations to a NSOperationQueue your createContainer operation will run first. When it has finished, the other operations will start running as their dependencies are now satisfied. You can also control how many operations you want to run concurrently using maxConcurrentOperationCount on NSOperationQueue.
As you will be using asynchronous API in your NSOperations you will need to implement a ConcurrentOperation and handle the state changes yourself. The API Reference is explaining this in pretty good detail.
Check out the API Reference for NSOperation for further information.
There is also a nice NSHipster article on NSOperations.
Adding to the NSOperationQueue answer, it's sometimes difficult to manually manage all the state changes that an NSOperation requires to handle something asynchronous like a network call.
To simplify that, you can use a Swift Library called Overdrive. It's an amazing library in which you simply subclass a Task class and write your network code in the run() function. And when you're done, you simply call self.finish to finish the task. Here's an example: Just create a simple download task:
Then, just add it to the queue.
You can also add dependencies between tasks, which basically solves your use case.
Hope this helps.
I want to know what is the proper way to use [self.operationQueue cancelAllOperations];
I am using a block operation in async to fetch results from my API. Sometimes it happens that I get result of first request after second request and those are displayed to user.
I am using AFNetworking library for operations. Any suggestion on how I can make sure that only one request (the latest one) is active at a particular time, and previous one gets cancelled automatically.
When all operations in a queue are cancelled it is the responsibility of each running operation to stop itself. The queue will only prevent future operations from starting. With block operations there isn't really any way to stop as the block doesn't have access to the operation to check if it's cancelled.
It isn't clear exactly what you're using the operation for, but you would need to crate an operation subclass, either to run or to wrap that logic, which at least checked for cancellation before running the final callback to return the result.
I'm trying to get my head around a asynchronicity; dispatch, multiple threads, run loops etc etc.
What's the difference between:
1) creating an NSURLRequest and NSURLConnection in a given method, and having it execute and us responding to the delegate methods (didReceiveResponse, didReceiveData, connectionDidFinishLoading, etc), and
2) creating a block and having it dispatch_async ?
With the first method it seems great that I have access to the delegate methods (do I still have access to those using dispatch?), and execution of the delegate methods are actioned when fired (or close to it?)
With the block/dispatch method, I'm guessing the block is processed synchronously within it's thread? And then comes back to the main thread to process the results? Example code I've been looking at:
dispatch_async(kBgQueue, ^{
NSData* data = [NSData dataWithContentsOfURL:
kLatestKivaLoansURL];
[self performSelectorOnMainThread:#selector(fetchedData:)
withObject:data waitUntilDone:YES];
});
So, the "self performSelector...." is performed AFTER the data is received? (what I meant before with synchronously - maybe the wrong term). And the next line of the block sends us back to the main thread.
What is the purpose of, or why is there a "waitUntilDone:YES"? Is it because if it's not there, other stuff could happen NOT in the main thread?
Is the first method above still only performed on the main thread?
and finally, what are the pros and cons of each in the case of a JSON query to a web page? Is there any great benefit of one method over the other?
1) When you use a NSURLConnection, either in your main thread or say in a NSOperation, you have full control of stopping it at any point, and tracking its progress. What you get back are delegate methods when various things happen, but you're not sitting and waiting for something to complete. If you want to stop it at anytime, you send it cancel, then you can release (or nil) it and forget about it.
2) So look at this. If you did this call in the main thread, it would wait until it succeeds or fails. Once started, it has to run to success or failure. This would block your UI if in the main thread. Put it in a block and run it on some other thread, and the same thing will happen - the chosen thread will block until the method ends. The use of 'self' to send the result will retain self. So if self is say a UIViewController, then even if you pop it (thinking its going to get removed), it stays around until this method completes, doing heaven knows what. This usage is very dangerous and may work often but fail catastrophically when a device has a crappy inet connection (for example).
The wait until does is to synchronize threads. If you want to know that the method has been run on the main thread, and only then proceed, use YES. If you just want the method queued and you're done (like in this case) you would just use NO.
The method will for sure be on the main thread - this Apple promises you with this method.
3) JSON
The majority of users I know use NSURLConnections from NSOperations or blocks. Operations can be cancelled (which would then cancel the connections) - so you can handle getting a 'Back' button press no matter how much is going on. If the query fails you can look at the html status (did you get a 400 or 500 error? a timeout? etc)
There is an open source project on github, hardly 200 lines of code, that provide an elegant and easy to use helper class to run operations (with demo code): /NSOperation-WebFetches-MadeEasy. I have personally used this code in over 8 apps still in the store with great success - a single OperationsRunner often has hundreds of fetches going on simultaneously, and the app has multiple classes running OperationsRunners at the same time.
If you process the JSON in the NSOperation, you will get real speedups on devices with multiple cores.
What is the differance between adding a operation which make a synchronous NSURLConnection request in NSOperationQueue ( or synchronous request from a thread ( not main thread)) AND making a asynchronous request from the main thread ?
Both will not block main thread so UI will remain responsive but is there any advantage of using one over other? I know in later method i can track request progress etc but assume that progress and other HTTP stuff is not important here.
They are very similar. The biggest problem with synchronous requests is that they can't easily be cancelled. Depending on your application, that could be a problem. Imagine you are downloading a big document and the user moves to another screen so you no longer need that information. In our case, I actually chose doing asynchronous NSURLConnections on a secondary NSThread, which may be overkill for some apps. It is more complicated, but it gives us the ability to both cancel requests and to decode the JSON/XML/image data on secondary threads so they don't impact main thread user interactivity.
Asynchronous requests are scheduled on the run loop and setup as a run loop source, triggering the code automatically only when there is data received from the network (as any socket source).
Synchronous requests running on a NSThread monopolizes a thread to monitor the incoming data, which is in general quite overkill.
You can always cancel an NSURLConnection even if it has been executed asynchronously, using the cancel method.
I bet using the new API that allows to send an asynchronous request on an NSOperationQueue (+sendAsynchronousRequest:queue:completionHandler:) uses GCD under the hood and dispatch_source_create, or something similar, so that it behave the same way as when an NSURLConnection is scheduled on the run loop, avoiding using an additional thread (watch the WWDC'12 videos that explains why threads are evil and their usage should be minimized), the difference only being that allows you to use a block to be informed upon completion instead of using the delegate mechanism.
Some years ago I created a class that embedded NSURLConnection asynchronous calls and delegate management into a nice block API (see OHURLLoader on my github) that makes it easier to use (feel free to take a look). I bet the new API that uses NSOperationQueues uses the same principle, still doing asynchronous requests on the runloop but allowing you to use blocks instead of having to implement a delegate.
The historical position was that there's an advantage in power consumption, and therefore battery life, in asynchronous requests — presumably including both the older delegate approach and the new block-based approach.