I'm implementing an iOS app which make requests using REST service. And I want to cancel all the previous REST calls when I make a new call. Can I do it in the global queue in GCD without Operation Queue? Thanks
GCD does not provide an API to cancel blocks. So you will have to implement this cancellation yourself.
The easiest way probably would be to set a global flag 'canceled' and check that inside of your blocks. If the flag is set, immediately return from your block. Then after all blocks have finished you can reset the flag and enqueue your new block.
Even though that sounds simple, this requires some nontrivial code. It would be much easier to use NSOperationQueue instead of reimplementing its features on top of plain GCD.
Related
We have a common Requesthandler.swift file which handles get, post http methods. We are using this file accross the App to have http request.
What should be the value for the delegateQueue, when we initialising the URLSession.
let session = URLSession(configuration: config, delegate: self, delegateQueue:OperationQueue.main)
The key consideration is that the queue should be a serial queue. As the docs say:
The queue should be a serial queue, in order to ensure the correct ordering of callbacks.
So, if you instantiate your own OperationQueue, make sure to set its maxConcurrentOperationCount to 1.
The docs go on to say:
If [the delegate queue is] nil, the session creates a serial operation queue for performing all delegate method calls and completion handler calls.
As such, we generally we would just leave this as nil, and let URLSession take care of this for us.
One generally would not use the main queue, though. This is largely a matter of convention (as URLSession.shared, which we generally use if we don’t need delegate methods or custom behaviors, uses a serial background queue). This practice, of using a serial background queue, is advisable, as you a lower the risk that some slow parsing operation (or whatever) in a delegate method or completion handler would ever affect your main thread responsiveness. That having been said, whenever using a serial background queue, make sure to dispatch UI updates (and the like) back to the main queue.
If you use it across the app for all http that is the correct way to do it. However, I would suggest not to create your own session. There is already something exactly for that, which is URLSession.shared, albeit with (just a few) limitations as discussed in the docs.
If you can live with the limitations great - use the shared session; otherwise use nil as Rob suggested or if you DIY the queue then you do NOT want to use main as your delegate queue. You definitely want a background queue here. If you DIY then you'd probably create a singleton queue and use that for all requests and configure it according to taste (and make it serial - see Rob's answer).
Finally, since the delegate will call the completion on the delegate queue, which is NOT main, you should switch to main in the completion whenever you need to update UI, so there will probably be a lot of switching to main there. That is not wrong nor telling you to use main as queue.
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.
I am doing a lot of GCD and asynchronous rendering and data retrieval work lately and I really need to nail the mental model about how asynchronous is done.
I want to focus on setNeedsDisplay and the NSURLConnectionDelegate suite of methods.
Is it correct to call setNeedsDisplay asynchronous? I often call it via dispatch_async(dispatch_get_main_queue(), ^{}) which confuses me.
The NSURLConnectionDelegate callbacks are described as asynchronous but are they not actually concurrently run on the main thread/runloop. I am a but fuzzy on the distinction here.
More generally in the modern iOS era of GCD what is the best practice for making GCD and these methods play nice together. I'm just looking for general guidelines here since I use them regularly and am just trying not to get myself in trouble.
Cheers,
Doug
No, you generally don't call setNeedsDisplay asynchronously. But if you're invoking this from a queue other than the main queue (which I would guess you are), then you should note that you never should do UI updates from background queues. You always run those from the main queue. So, this looks like the very typical pattern of dispatching a UI update from a background queue to the main queue.
NSURLConnection is described as asynchronous because when you invoke it, unless you used sendSynchronousRequest, your app immediately returns while the connection progresses. The fact that the delegate events are on the main queue is not incompatible with the notion that the connection, itself, is asynchronous. Personally, I would have thought it bad form if I can some delegate methods that were not being called from the same queue from which the process was initiated, unless that was fairly explicit via the interface.
To the question of your question's title, whether NSURLConnection uses GCD internally, versus another concurrency technology (NSOperationQueue, threads, etc.), that's an internal implementation issue that we, as application developers, don't generally worry about.
To your final, follow-up question regarding guidelines, I'd volunteer the general rule I alluded to above. Namely, all time consuming processes that would block your user interface should be dispatched to background queue, but any subsequent UI updates required by the background queue should be dispatched back to the main queue. That's the most general rule of thumb I can think of that encapsulates why we generally do concurrent programming and how to do so properly.
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.
I am using dispatch_async and a block to retrieve server data every 3 seconds or so. What is the method of handling the view either disappearing or the user shutting the program down?
Would it be a boolean flag that the async block checks every now and then? If so, what if the view exits while the async block is sleeping?
You cannot easily cancel a dispatch call, so your best bet is to move to an NSOperation instead. There is a highly relevent video from WWDC 2012, Session 211 - Building Concurrent User Interfaces on iOS which covers precisely the kind of problem you describe. I definitely suggest you watch it.
The basic approach is to create an NSBlockOperation which can check the -isCancelled property on itself to return early if it gets cancelled. Then you can cancel the operation in viewDidDisappear.
An alternative approach would be to use NSTimer which can also be easily invalidated/cancelled. This might actually be the simplest solution for you given the description of what your code is doing.