Do you need to consider thread-safety using NSURLConnection? - iOS - ios

I've just been wondering for a while now how exactly asynchrounous requests work with NSURLConnection.
For example, suppose you have several upload processes running in your application, all initialized using different instances of NSURLConnection. As uploading processes, your wrapper objects gets the NSURLConnection delegate methods called, like:
-(void)connectionDidFinishLoading:(NSURLConnection*)connection;
Suppose that in all your NSURLConnection wrapper objects share the same delegate object which have a list of all active uploads in an array, and that when the connectionDidFinishLoading gets called for all your connections, they go in and remove themself from that list in the shared delegate object.
The question then is, do you have to worry about thread-safety when those connection objects can access the same array? Or does all those delegate methods go back to the main-thread in such a way that you are not supposed to worry about thread-safety?

The trick is that the delegate methods are called on the thread on which you created your NSURLConnection, which unless you specifically change it will be the main thread. The OS uses one of the threading Queueing APIs to call the delegate method over and over on that thread in the order each connection finishes.
With NSURLConnection its only really the transfer that needs to be threaded. If the transfer happened on the main thread then during the transfer the User wouldn't be able to interact with your iOS application. Doing stuff with the result takes a relatively short time, but if it takes a long time whether you choose to do that processing in the background (on a different thread) or not is then up to you.

Related

Is it a good approach to use multiple download tasks with a single URLSessionDownloadDelegate confirming class?

Currently I'm working on implementing a network manager for handling download and upload tasks. I have a class that confirms to URLSessionDownloadDelegate, URLSessionDelegate. The problem I'm facing is I'm using a single session object which is used for all the service calls. So when multiple network operations are being processed, all the response call backs will be handled in the class that is implementing the delegate methods. So to find for which call a response has been arrived, I'm comparing the task parameter of the delegate method and all the tasks that are running currently(I have closure property for each of the delegate methods in the class that confirms to session protocols). Is there any other ways to achieve this result ?(I think this won't be a good solution when handling large number of requests)
Ideally, you shouldn't be doing comparisons yourself, but rather should store the closures in a dictionary keyed by the task objects. Be sure to update the dictionary in any delegate methods that replace one task with another. And be sure to do dictionary lookups and stores on the same thread or serial queue every time.

What is the best networking solution for a complex multithreaded app?

I have a streaming iOS app that captures video to Wowza servers.
It's a beast, and it's really finicky.
I'm grabbing configuration settings from a php script that shoots out JSON.
Now that I've implemented that, I've run into some strange threading issues. My app connects to the host, says its streaming, but never actually sends packets.
Getting rid of the remote configuration NSURLConnection (which I've made sure is properly formatted) delegate fixes the problem. So I'm thinking either some data is getting misconstrued across threads or something like that.
What will help me is knowing:
Are NSURLConnection delegate methods called on the main thread?
Will nonatomic data be vulnerable in a delegate method?
When dealing with a complex threaded app, what are the best practices for grabbing data from the web?
Have you looked at AFNetworking?
http://www.raywenderlich.com/30445/afnetworking-crash-course
https://github.com/AFNetworking/AFNetworking
It's quite robust and helps immensely with the threading, and there are several good tutorials.
Are NSURLConnection delegate methods called on the main thread?
Yes, on request completion it gives a call back on the main thread if you started it on the main thread.
Will nonatomic data be vulnerable in a delegate method?
Generally collection values (like array) are vulnerable with multiple threads; the rest shouldn't create anything other than a race problem.
When dealing with a complex threaded app, what are the best practices for grabbing data from the web?
I feel it's better to use GCD for handling your threads, and asynchronous retrieval using NSURLConnection should be helpful. There are few network libraries available to do the boilerplate code for you, such as AFNetworking, and ASIHTTPRequest (although that is a bit old).
Are NSURLConnection delegate methods called on the main thread?
Delegate methods can be executed on a NSOperationQueue or a thread. If you not explicitly schedule the connection, it will use the thread where it receives the start message. This can be the main thread, but it can also any other secondary thread which shall also have a run loop.
You can set the thread (indirectly) with method
- (void)scheduleInRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode
which sets the run loop which you retrieved from the current thread. A run loop is associated to a thread in a 1:1 relation. That is, in order to set a certain thread where the delegate methods shall be executed, you need to execute on this thread, retrieve the Run Loop from the current thread and send scheduleInRunLoop:forMode: to the connection.
Setting up a dedicated secondary thread requires, that this thread will have a Run Loop. Ensuring this is not always straight forward and requires a "hack".
Alternatively, you can use method
- (void)setDelegateQueue:(NSOperationQueue *)queue
in order to set the queue where the delegate methods will be executed. Which thread will be actually used for executing the delegates is then undetermined.
You must not use both methods - so schedule on a thread OR a queue. Please consult the documentation for more information.
Will nonatomic data be vulnerable in a delegate method?
You should always synchronize access to shared resources - even for integers. On certain multiprocessor systems it is not even guaranteed that accesses to a shared integer is safe. You will have to use memory barriers on both threads in order to guarantee that.
You might utilize serial queues (either NSOperationQueue or dispatch queue) to guarantee safe access to shared resources.
When dealing with a complex threaded app, what are the best practices for grabbing data from the web?
Utilize queues, as mentioned, then you don't have to deal with threads. "Grabbing data" is not only a threading problem ;)
If you prefer a more specific answer you would need to describe your problem in more detail.
To answer your first question: The delegate methods are called on the thread that started the asynchronous load operation for the associated NSURLConnection object.

What's the difference between performing an NSURLRequest and responding to delegates as opposed to using dispatch_async?

I'm trying to get my head around a asynchronicity; dispatch, multiple threads, run loops etc etc.
What's the difference between:
1) creating an NSURLRequest and NSURLConnection in a given method, and having it execute and us responding to the delegate methods (didReceiveResponse, didReceiveData, connectionDidFinishLoading, etc), and
2) creating a block and having it dispatch_async ?
With the first method it seems great that I have access to the delegate methods (do I still have access to those using dispatch?), and execution of the delegate methods are actioned when fired (or close to it?)
With the block/dispatch method, I'm guessing the block is processed synchronously within it's thread? And then comes back to the main thread to process the results? Example code I've been looking at:
dispatch_async(kBgQueue, ^{
NSData* data = [NSData dataWithContentsOfURL:
kLatestKivaLoansURL];
[self performSelectorOnMainThread:#selector(fetchedData:)
withObject:data waitUntilDone:YES];
});
So, the "self performSelector...." is performed AFTER the data is received? (what I meant before with synchronously - maybe the wrong term). And the next line of the block sends us back to the main thread.
What is the purpose of, or why is there a "waitUntilDone:YES"? Is it because if it's not there, other stuff could happen NOT in the main thread?
Is the first method above still only performed on the main thread?
and finally, what are the pros and cons of each in the case of a JSON query to a web page? Is there any great benefit of one method over the other?
1) When you use a NSURLConnection, either in your main thread or say in a NSOperation, you have full control of stopping it at any point, and tracking its progress. What you get back are delegate methods when various things happen, but you're not sitting and waiting for something to complete. If you want to stop it at anytime, you send it cancel, then you can release (or nil) it and forget about it.
2) So look at this. If you did this call in the main thread, it would wait until it succeeds or fails. Once started, it has to run to success or failure. This would block your UI if in the main thread. Put it in a block and run it on some other thread, and the same thing will happen - the chosen thread will block until the method ends. The use of 'self' to send the result will retain self. So if self is say a UIViewController, then even if you pop it (thinking its going to get removed), it stays around until this method completes, doing heaven knows what. This usage is very dangerous and may work often but fail catastrophically when a device has a crappy inet connection (for example).
The wait until does is to synchronize threads. If you want to know that the method has been run on the main thread, and only then proceed, use YES. If you just want the method queued and you're done (like in this case) you would just use NO.
The method will for sure be on the main thread - this Apple promises you with this method.
3) JSON
The majority of users I know use NSURLConnections from NSOperations or blocks. Operations can be cancelled (which would then cancel the connections) - so you can handle getting a 'Back' button press no matter how much is going on. If the query fails you can look at the html status (did you get a 400 or 500 error? a timeout? etc)
There is an open source project on github, hardly 200 lines of code, that provide an elegant and easy to use helper class to run operations (with demo code): /NSOperation-WebFetches-MadeEasy. I have personally used this code in over 8 apps still in the store with great success - a single OperationsRunner often has hundreds of fetches going on simultaneously, and the app has multiple classes running OperationsRunners at the same time.
If you process the JSON in the NSOperation, you will get real speedups on devices with multiple cores.

NSURLConnection synchronous request from a thread vs asynchronous request

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.

why my background working thread is blocking UI thread?

I am working on an app, which uploads native contacts to server then get responses(JSON, a contact list that already installed the app). When native contacts are large enough, server response will be slow and unstable. And user cannot do other things. so I put network request into background thread. every time I will upload 100 contacts, do some tasks , then next 100 contacts until loop finish.
But in running, the result is not as expected. background thread is running, it keeps to request server. UI thread is blocked, I still cannot do anything.
is this cause a long loop in background thread? Although I have 2 thread, but they will compete CPU resources(test device is iPod, 1 core. And I think this may not related core numbers)?
Could anyone tell me hints on how to handle this kind of scenario? Thanks in advance!
Update:
I have found the root cause. A global variable in App delegate is set to wrong value, therefore UI behavior is weird. I found this by comment all network request method. So this problem is not related with multiple threading. Sorry for the bother.
I think there needs to be some clarification as to how you are performing the network operations.
1st, NSOperatiomQueue deals with NSOperations, so you are presumably wrapping your network code in an NSOperation subclass.
2nd, are you using NSURLConnections for your networking code?
3rd, is the blocking part the NSURLConnection or you delegate callback for NSURLConnection?
1 thing to note is that plain ol' NSURLConnections are implemented under the hood multithreaded. The object is placed into your main threads run loop by default (when run from the main thread), but the object is just a wrapper that handles callbacks to the delegate from the lower level networking code (BSD sockets) which happens on another thread.
You really shouldn't be able to block your UI with NSURLConnections on the main thread, unless A) you are blocking the thread with expensive code in the delegate callback methods or B) you are overwhelming your run loop with too many simultaneous URL connections (which is where NSOperationQueue's setMaxConcurrentOperationsCount: comes into play)

Resources