I need to call multiple web services in a loop for uploading and downloading the data for application.(Known as Sync Process)
I am using AFHTTPSessionManager and create a subclass/wrappper class for that.
I need to do something in a que or creating batch request for that.
I am stuck at this from last night.
Thanks in advance.
For this kind of funcionalities probably an AFHTTPRequestOperationManager is a better choice.
SessionManager relies on tasks, tasks don't have the knowledge of dependency between each other, while operations does.
You have different possibilities:
Wrap sessions into a dispatch_group take a look here
Try to embed a session task inside an NSOperation (really hard)
Use AFHTTPOperation and add dependencies between operations
Use a serial queue on GCD
You might find also this answer helpful
Related
I have an app on iOS which wants to download data from my server. The data is nothing but simple text files. I would like to download these files in parallel.
I am getting confused if I should be creating multiple instances of nsurlsession or multiple tasks(NSURLSessionTasks) under one nsurlsession.
I do know nsurlsession APIs are thread safe. And my fundamental confusion here is about following thing:
My NsurlsessionConfiguration is going to be same for the entire time. So, ideally I can use the same instance of NSURLSession for every file.
But does it make sense to create multiple instance of NSURLSessionTasks in parallel?
Or better approach is to take make a new NSURLSession for achieving the parallelism.
I am confused to understand if every NSURLSessionTask in the same NSURLSession creates a new end point or it is serialized.
One session with many tasks -- one per request -- will work safely concurrently. Whether the client makes requests across many servers or to a single one makes no difference so long as the concurrency is less than HTTPMaximumConnectionsPerHost which is part of the session config.
The tasks run in parallel. (It's actually pretty hard to find a place in the docs where those words appear explicitly, but there's pretty good implication here).
Notice that session configs have a delegateQueue. The rationale is -- because the sessions tasks are run concurrently -- the app level needs to serialize handling of the results, lest two parallel tasks step on each other via the delegate.
The question is if an app should have one instance of the queue for all async operations, or several queues can be created?
With one queue it's pretty simple because all tasks are executed based on assigned priority. So for me it's more favourable because there is no need to write extra code.
In the case of multiple queues at least one of them should be main.
So some sort of queue manager should be implemented that will be able to suspend "sub" queues and allow execution of operations from main queue if needed.
The analogy with only one single connection to database make me think that the one centralised queue should be used for all async operations.
So what would you recommend? What are the best practices?
After doing some searching and brainstorming I came up to the solution.
In my application I'm going to use 2 async queues:
one queue (NSOperationQueue) for all background operations (like parsing of downloaded .json files) and another queue (which is already implemented by NSURLSession class) for requests (API requests, downloading images, etc).
this is an open question aiming at understanding what is the best practice or the most common solution for a problem that I think might be common.
Let's say I have a list of URLs to download; the list is itself hosted on a server, so I start a NSURLConnection that downloads it. The code in connectionDidFinishLoading will use the list of URLs to instantiate one new NSURLConnection, asynchronously, per each URL; this in turn will trigger even more NSURLConnections, and so on - until there are no more URLs. See it as a tree of connections.
What is the best way to detect when all connections have finished?
I'm aiming the question to iOS7, but comments about other versions are welcome.
A couple of thoughts:
In terms of triggering the subsequent downloads after you retrieve the list from the server, just put the logic to perform those subsequent downloads inside the completion handler block (or completion delegate method) of the first request.
In terms of downloading a bunch of files, if targeting iOS 7 and later, you might consider using NSURLSession instead of NSURLConnection.
First, the downloading of files with a nice modest memory footprint is enabled by initiating "download" tasks (rather than "data" tasks).
Second, you can do the downloads using a background NSURLSessionConfiguration, which will let the downloads continue even if the user leaves the app. See the Downloading Content in the Background section of the App Programming Guide for iOS. There are a lot of i's that need dotting and t's that need crossing if you do this, but it's a great feature to consider implementing.
See WWDC 2013 What's New in Foundation Networking for an introduction to NSURLSession. Or see the relevent chapter of the URL Loading System Programming Guide.
In terms of keeping track of whether you're done, as Wain suggests, you can just keep track of the number of requests issued and the number of requests completed/failed, and in your "task completion" logic, just compare these two numbers, and initiate the "all done" logic if the number of completions matches the number of requests. There are a bunch of ways of doing this, somewhat dependent upon the details of your implementation, but hopefully this illustrates the basic idea.
Instead of using GCD you should consider using NSOperationQueue. You should also limit the number of concurrent operations, certainly on mobile devices, to perhaps 4 so you don't flood the network with requests.
Now, the number of operations on the queue is the remaining count. You can add a block to the end of each operation to check the queue count and execute any completion logic.
As Rob says in his answer you might want to consider NSURLSession rather than doing this yourself. It has a number of advantages.
Other options are building your own download manager class, or using a ready-made third party framework like AFNetworking. I've only worked with AFNetworking a little bit but from what I've seen its elegant, powerful, and easy to use.
Our company wrote an async download manager class based on NSURLConnection for a project that predates both AFNetworking and NSURLSession. It's not that hard, but it isn't as flexible as either NSURLSession or AFNetworking.
I have subclassed AFHTTPSessionManager and added some methods specific to my implementation. I have a couple questions around using my subclass as a singleton and concurrency:
Is creating a singleton of AFHTTPSessionManager still a best practice? (AFNetworking 2.0, iOS7)
If I make requests via a singleton of the subclass using the [self GET/POST method does this support concurrent
operations? E.g., I have a slow sync running and then do an search. Will the search begin immediately or wait for the sync to complete? Or, asked another way, are these operations on independent operation queues?
You asked:
Is creating a singleton of AFHTTPSessionManager still a best practice? (AFNetworking 2.0, iOS7)
I'm not sure if it ever was best practice. Singletons are frequently derided (see What's wrong with singleton?, which has links to lots of arguments against singletons). They are convenient, but for most apps, a singleton for the session manager is unnecessary. My general counsel is that you shouldn't use a singleton unless you have some compelling need to do so.
This is a subject of opinion and debate (which is explicitly frowned upon on Stack Overflow), so I would not suggest we pursue that question further. Follow the links in the above Stack Overflow question, and you'll see many opinions expressed there.
If I make requests ... does this support concurrent operations?
Yes, the network requests run asynchronously and support concurrent operations.
Are these operations on independent operation queues?
At the time I write this, the requests generated via AFHTTPSessionManager are not run on operation queues at all. The session's manager NSURLSession manages the tasks itself.
On the other hand, the NSURLConnection-based AFHTTPRequestOperationManager will run GET and POST requests on a single, concurrent operation queue. If you manually create your own AFHTTPRequestOperation, you can add them to your own queues if you want.
But all of this is academic. I think your real question is whether GET and POST requests run asynchronously, and the answer is "yes". And if the question is whether they run concurrently with respect to each other, again, the answer is "yes".
I'm developing an application which must extract new messages for user from the server. I have implemented this as a timer which fires every 2 seconds and call a selector which is a method that implement HTTP request and server respond processing. So I think it is quite a bad idea to do this in a main thread.I have no experience with multithreading in iOS. So I want to know what fits well for parallelizing of this task: GCD or NSThread?
You should work as far up the API stack as possible. That way you can concentrate on programming functionality and not managing threads. GCD uses threads that the system has gotten going anyway and its much more efficient than managing your own code. Its even better to aim to encapsulate your networking into NSOperations that can then be put on an NSOperationQueue and these will be executed on one or more background threads, whatever the system deems is a good number for the current power status and other things like that.
The benefit of NSOperation over a pure GCD approach is that operations can be cancelled. Once a block is committed to GCD it has to run no matter what.
If you want to encapsulate your HTTP requests in NSOperations you might be interested to know that someone has already done this for you. AFNetworking is one of the most widely regarded iOS networking stacks and uses NSOperations as its base to build on and as such is very easily multi threaded.
A good idea would be to try and encapsulate your parsing code into an NSOperation and then as your network request operations return you can create parsing operation instances and put them on another queue for processing in the background.