4

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?

Madivad
  • 2,999
  • 7
  • 33
  • 60
  • I thought I would add, I have a dozen (actually, more) tabs open while I've been trying to learn/understand this tonight. I think because most of the examples are completely different, I haven't been able to relate the two. Also, I have been trying to do the same thing the two different ways in my app (for testing purposes), but I just keep getting it wrong. In relation to the "waitUntilDone" param, to me it looks superflous, since it's the last action in the block and irrelevant. But I am only guessing. – Madivad Nov 17 '12 at 12:41

1 Answers1

2

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.

David H
  • 40,852
  • 12
  • 92
  • 138
  • Thanks @David, for number 2 though, if the action being performed in the "fetcheddata" method is merely displaying something on the UI, is it halting the main thread? I thought that was the idea of dispatch_async, that it pretty much performed similarly to option 1 in that the main run loop continues and comes back to it in cycles. – Madivad Nov 18 '12 at 02:38
  • Also, isn't the first option still performed on the main thread? That is, if I have just used NSURLConnection without some thread creating operation? I think I'm mainly confused, because I see them both operating on the main thread. I do much prefer option 1 purely for the reasons you've stated. Thanks also for the link, I'll dig through that tonight and hopefully it'll all hit home a little better :-) – Madivad Nov 18 '12 at 02:41
  • My point in two is that all the work in the NSData method is itself performed on a different thread, and it blocks until it completes - regardless of what thread it is called from. The final fetchedData: method takes virtually no time - it's queued on the runloop of the specified thread. In 1), work is done on main thread, but no blocking occurs. The delegate methods execute quickly and you can cancel as needed. So your UI will be responsive. For some small number of connections this is fine. For hundreds using operations running in the background works better for most people. – David H Nov 18 '12 at 12:53
  • Thanks Dave. Marked appropriately. – Madivad Nov 19 '12 at 00:22