Best way to set requests in background - ios

In my iOS5-App I do a lot of Request, parsing the results and storing them in CoreData simultaneously.
For doing the requests I use asynchronous ASIHttpRequest.
But the app has perfromance problems while this requests are running. What is a good approach to to this in the background? And how do I avoid conflicts with the context when storing the results to the db? All "commits" are performed in the main-thread because I had problems when putting the requests in a backgroundque.
Can you give me an example or a good pattern to use in my app?

Since ASI is no longer being supported a lot of people switched to AFNetworking.
There's also the minimalistic approach of using NSURLConnections with Blocks.

Related

What‘s the best practices of NSURLSession?

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

Async NSURLConnection triggering other Async NSURLConnection: what is the best way of doing this?

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.

What I should use for parallelisation of frequent HTTP requests to the REST server in iOS application: GCD or NSThread?

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.

Dropbox API request pattern

I am using the Dropbox SDK on iOS, and am mirroring a remote directory locally. I understand the basic usage pattern - make a request, wait for the delegate to be called with the results.
When I have a large number of requests to perform, should I serialize them by waiting for the result before making the next call, or make all requests at once and then just wait for them each to come in? Does the Dropbox SDK handle the latter case intelligently (e.g. with an NSOperationQueue), or am I better off doing this myself?
If I am better off handling request queuing myself, should I change behavior when the user is on a wifi vs. cellular connection?
EDIT: I have seen CHBgDropboxSync and other existing solutions. My app requires more control over syncing than these provide, so I need to roll my own.
Depends on how many requests you need to make and how reliant they are on each other. With either GCD or NSOperation you can daisy-chain requests, you can issue them all at once and keep semaphores in your program, or you can make requests rely on others to complete. You're creating an asynchronous state machine, and its design will depend on whether that state machine is dynamic or static.

Use Core data as browser cache in AFNetworking

I read something about multi thread access on DB but still not sure best way to do that for reading/writing in conjunction with async network download.
For instance I will have a page with images from the web, so I'm retrieving them by their URLs, using AFNetworking but I want to check first on my DB and write on it (or disk) the retrieved image for future use.
What can be the best way to do that without blocking the UI (like when scrolling)?
If I do that with a singleton that reads/writes it block the main thread.
Thanks for any tips on that.
AFNetworking is not the tool for that. Instead, you can take advantage of the built-in functionality of NSURLCache--specifically Peter Steinberger's fork of SDURLCache.
In -applicationDidFinishLaunchingWithOptions:, do NSURLCache +setSharedCache: with an instance of SDURLCache (with some amount of disk space allocated). All requests made through UIWebView (and AFNetworking, for that matter) will automatically be routed through NSURLCache before the request is made to check the cache. It's unobtrusive, drop-in, and follows cache directives correctly, and it should solve your problem quite nicely.

Resources