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.
Related
Subscribe my app first:
Most scenes use AFNetworking, a small part of scenes use NSURLSession.sharedSession or create a new NSURLSession.
Using one URLProtocol instance to handle almost all requests, and at the end of -startLoading function, using only one NSURLSession to resume all tasks.
My question is:
I know URLSession instance will cause memory growth and it persists for about 10 minutes, so what is the maximum limit for an app to hold URLSession instances?
What‘s the best practices of NSURLSession?Is it recommended to use only one URLSession instance for the entire app? Or a fixed domain uses a fixed NSURLSession( A-domain using A-session, B-domain using B-session)?
Should I create several URLProtocol instances to handle different domain requests
Thanks!
You want to use as few URLSessions as necessary. Usually, this is only one and it's also unlikely you invalidate this session and create a new one during the lifetime of the app.
The reason for having as few as possible, is that URLSession is specifically designed to handle more than one network request - both executing them in parallel or sequential - and can optimise all requests executed in this session in order to use less memory, less power and achieve faster execution times.
On the other hand, there are far less options to optimise requests executed in different URLSessions. Especially performance gains from using HTTP/2 cannot be achieved for requests running in different URLSessions.
However, there may be requirements or situations where you create more than one. For example, you utilise a third party image loading library which creates its own URLSession. Or you need distinct URLSession configurations, like cellular usage, cooky policy or cache policy, etc., which cannot be shared.
Or for example, you want to tie a certain URLSession and it's URLCache and Credential cache to a certain authenticated user. When you have some "sign-out" feature in your app, you can invalidate the session, clear the credential storage and the URLCache. At the same time you have another URLSession for your "public" API, and another URLSession for your image loading, which are not affected by a "sign-out" - and where cached responses should be kept.
It's a gross no-no to create a URLSession for every request, then let this hang around when the request completes and create another URLSession with the next request. You can't do it worse than this.
See also
Apple Developer Forum
WWDC: NSURLSession: New Features and Best Practices
WWDC: Networking with NSURLSession
I'm developing an iOS app and have been looking into using Bolts framework by Parse (facebook) to manage network operations (using Alamofire for network requests).
I'm wondering if there is a good implementation/pattern out there for a task queue for Bolts. I need to have offline functionality and therefore I (think) need to have some sort of task queue so if the user is offline all of their save/create operations are saved (queued and persisted) and then executed once they have a network connection, also needed for retries of requests. I've looked at NSOperation queue so I may go that route although I like how Bolts does things with BFTask and would prefer to use that.
I understand your problem, but I think that you mix up the purpose of NSOperation queue and BFTasks a little bit.
BFTasks are used in order to use and create asynchronous and synchronous methods/network requests in a cohesive and minimalistic way. For instance, suppose that would have to login a user, present a search view and then download user`s search query results.
In order to keep your app optimized and have the UI at 60fps you would need to run your network request asynchronously. Apparently, you would present search view only if user logged in (using your method) (this technique is called "async tasks in series") and then you would download search results using parallel async requests (Think about downloading movie artworks for a movie name query in iTunes. They start downloading at the same time, "in parallel" to each other, so user images are downloaded independently from each other). (Whereas this is one is called "async tasks in parallel").
As you can see from this example, we can only achieve the desired logic along with desired performance if we use sequential and parallel async requests.
Bolts framework allows you to achieve all of the aforementioned logic in a VERY cohesive and convenient way.
NSOperation queue, on the other hand, allow you to build a complex sequence of both sync and async methods. It even allows you to get the status of a particular operation and bind dependencies. A good example of it, is view controller lifecycle.
If I were you, I would first learn how to use Bolts and NSOperation queue apart from each other. Then, depending on what you actually need to achieve in your app in terms of functionality, I would start thinking about binding Bolts and NSOperation queue in a class or a struct (in case you use swift). Like using Bolts for "online" stuff (executing network requests) and NSOperation queue for "offline" (storing the sequence of actions the user makes while being offline, in order to execute this sequence when the internet connection is back).
You can read more about NSOperation here and about Bolts for iOS here.
UPDATE:
In terms of implementation pattern, one suggestion that you might want to consider is to create a simple class/struct that would be responsible for storing("stacking") your Bolts methods. You can use arrays for sequential logic and sets for parallel one. You can also use sets to easily make sure that some of the requests happen only once as sets store only unique objects. Honestly, in my opinion, you should try to implement something similar to what I described, because Bolts itself (almost for sure) incorporates NSOperation and NSOperaitionQueue.
By the way, since Parse iOS SDK is open source right now, you could see how they implement saveEvenutually method which saves an object when internet connection is back and think how you could replicate their logic according to your needs.
I was going through this excellent blog post
(http://www.humancode.us/2014/08/14/target-queues.html)
of target threads in iOS and I could not help but wonder why do we need such a mechanism. In the example, we are specifying a serialised target queue for a custom concurrent queue. Can we not achieve the same by executing the blocks in the original concurrent queue in a serialised queue instead?
Whats the point of having a serialised target queue for a concurrent queue????
If I got You right, you're asking why would someone start serial task on a concurrent queue.
You would need that kind of behaviour in case, if most tasks with some resource can be performed concurrently (aka, simultaneously), but some tasks are, by nature, unsafe to be performed concurrently with others.
The most common example is readers/writers problem. Here you are accessing, for example, some resource of a file system. It's ok to read it even from different threads - every reader will get exactly what it needs. But here comes necessity to update contents of that file. Modifying it while someone reads it leads to unpredicted results - reader is not guaranteed to get the right, expected, info (partially from old version, partially from new). Even worse - there can be two writers (if file contents changes by application user and from some central storage via net) - result will be some crazy mix of two versions (actually, it can be now even corrupted)
Here comes necessity for each writer to wait till all other tasks performed (no one reads, no one writes), and for each reader to wait until no writing tasks take place (no one writes, no matter how many readers)
Wikipedia has nice article on this one. I haven't run into any other practical situations, where you would need this, but I believe there're more of them.
Hope it answers your question
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'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.