I'm developing a network based iOS app that downloads json data from the server and processes it. Both the downloading task and processing task can take a significant time to complete, So I don't want to perform either on the main thread.
I think there are 2 ways to do this:
Perform asynchronous loading using NSURLConnection and in the didFinishLoading method use GCD (say) to do the processing in background.
Use GCD's dispatch_async (say) to start work in background and use NSURLConnection's sendSynchronousRequest:returningResponse:error to download the data synchronously, Do the processing of the data, And call UI updates on the main thread.
I think the 2nd method would be easier to write and would produce cleaner code, Especially if one "download/process data" task involves multiple sequential service calls for data download. So rather than execution going like:
main (start) -> background (download) -> main (NSURLConnectionDelegate method) -> background (data processing) -> main (UI update)
We would have:
main (start) -> background (download) -> background (data processing) -> main (UI update)
which seems to be cleaner to me.
I found 2 similar questions: Good pattern for Internet requests with Grand Central Dispatch?
And
NSURLConnection and grand central dispatch
And the answers to both seem to suggest using something conceptually similar to method 1.
Is there no proper way to achieve what's described in method 2?
Thanks in advance!
I would not be inclined to pursue option #2. Although it enjoys a certain simplicity, sendSynchronousRequest does not afford progress updates during the download, the ability to cancel the request (and other more complicated scenarios). A NSURLConnectionDataDelegate approach gives you far more control over the network requests.
This question presumes GCD-based patterns, but I think operation queue patterns merit consideration. You can marry the control offered by the NSURLConnectionDataDelegate methods with cancelable operations that encapsulate the network request. When you start to get more sophisticated, you can start employing concurrent requests, but also constrain the degree of concurrency (e.g. not more than five concurrent requests).
I'd suggest taking a look at AFNetworking. Maybe you don't want to use that framework, but I'd still take a look at the operation-queue-based patterns it employs. I'd personally use that pattern over either of the aforementioned GCD approaches.
Related
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).
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.
I am confused on where to use which multithreading tool in iOS for hitting services and changing UI based on service data,
firstly I got accustomed to using NSURLConnection and its delegates, used didreceiveresponse, didreceivedata etc delegates to achieve the task
secondly I learned and used GCD to hit services and update the UI from within the block code
Now I am learning to use performSelectorInBackground() to do work in background thread
Clearly confused on which tool to use where?
NSURLConnection with delegate calls is "old school" way of receiving data from remote server. Also it's not really comfortable to use with few NSURLConnection instances in a single class (UIViewController or what not). Now it's better to use sendAsynchronousRequest.. method with completion handler. You can also define on which operation queue (main for UI, or other, background one) the completion handler will be run.
GCD is good for different tasks, not only fetching remote resources with initWithContentsOfURL: methods. You can also control what type of queues will receive your blocks (concurrent, serial ,etc.)
performSelectorInBackground: is also "old school" way of performing a method in background thread. If you weren't using ARC, you'd need to setup separate autorelease pool to avoid memory leaks. It also has a limitation of not allowing to accept arbitrary number of parameters to given selector. In this case it's recommended to use dispatch_async.
There are also NSOperationQueue with NSOperation and its subclasses (NSInvocationOperation & NSBlockOperation), where you can run tasks in the background as well as get notifications on main thread about finished tasks. IMHO They are more flexible than GCD in a way that you can create your own subclasses of operations as well as define dependencies between them.
The most important thing is, that you never change UI anyway in another thread except the main thread.
I think, that all points you mentioned use the same technique in the background: GDC. But I'm not sure of that.
Anyway it doesn't matter which tool you should use in terms of threading.
It's rather a question of your purpose. If you wan't to fetch an small image or just few data you can use contentsOfURLin a performSelectorInBackground() or a GDC dispatch block.
If it's about more data and more information like progress or error handling you should stick with *NSURLConnection`.
I suggest using GCD in all cases. Other techniques are still around but mainly for backward compatibility.
GCD is better for 3 reasons (at least):
It's extremely easy to use and the code remains very readable because of the use of blocks
It is lower level than things like NSOperation so it is much faster when you need high performance multi threading
It's lightweight and non-intrusive so your code doesn't have to change substantially when you want to add thread management in the middle of a method.
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.
Can someone explain the relationship between asynchronous NSURL requests and GCD and NSOperationQueues?
I am not sure when to use each.
Right now, I have been "getting away" with asynchronous NSURL requests when I need to fetch/upload data to the server. But it has been suggested that I should use GCD. My problem is I do not know in what real life examples GCD would be better. Does anyone have any common use cases for me? And if I use GCD to store a queue of 10 asynchronous NSURL GET requests, for example, how would this benefit me? Does it even make sense to have an asynchronous NSURL request inside grand central dispatch queue or an NSOperationQueue?
Thank you!
What is particularly confusing in your case is that we're mixing an HTTP request queue (where requests would be sent one after the other) and an operation queue (where random computational work is executed one task after the other).
A standard NSURLConnection instance calls its delegate on the main thread, which is OK if you're not doing complex work on the data or on your UI at that time. But say you need to download a big file and write it chunk by chunk as a file on disk, all while scrolling down a table view. Now your scrolling might get choppy when you write data on the disk, blocking the main thread.
That's where GCD or its higher level abstraction NSOperationQueue comes into play. To solve this issue, you need to offload your data write calls off of the main thread. You can do that by specifying an NSOperationQueue instance on your NSURLConnection via setDelegateQueue:. This will ensure your delegate, and therefore your write calls, will be called in a background thread. You can also leave the delegate calls on the main thread, and wrap your expensive write calls inside a block which you will then execute off the main thread with dispatch_async. Now NSOperationQueue basically wraps a dispatch queue, and you're avoiding an extra thread switch by using it over a raw dispatch queue so I would recommend the NSOperationQueue solution (which also happens to looks simpler).
AFNetworking is a great library, and it solves this issue in a third way: it fires off an NSThread which is dedicated to NSURLConnection delegate calls. That's the pre-GCD way of offloading work off the main thread. Although it works, GCD offers a more efficient and good-citizen way of presenting your background work to the system.
Last, if you're looking for an HTTP request queue, Cocoa doesn't provide it. You will have to either build a scheduler yourself, or as you already figured it out use AFNetworking which again is a great choice.
If you're interested in this topic, GCD has a lot more to offer than just hosting NSURLConnection delegate calls, and I would recommend you read Apple's great Concurrency Programming Guide or watch the excellent WWDC 2011 videos on GCD (Blocks and Grand Central Dispatch in Practice and Mastering Grand Central Dispatch).
This is off the topic but if you use AFNetworking Lib you dont have to do anything you mentioned above.
"AFNetworking is a delightful networking library for iOS and Mac OS X. It's built on top of NSURLConnection, NSOperation, and other familiar Foundation technologies. It has a modular architecture with well-designed, feature-rich APIs that are a joy to use. "
Answer to your question, please read this
http://www.cocoaintheshell.com/2011/04/nsurlconnection-synchronous-asynchronous/