I am using GCD
to send HTTP
request asynchronously. Here is the code that doesn't work:
dispatch_async(connectionQueue, ^{
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:[NSString stringWithFormat:someURL]]];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection start];//Not working
});
the above code is not working at all. I am not getting any call back in NSURLConnectionDelegate's methods.
But when i tried the following code, everything worked fine and i got proper callbacks
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:[NSString stringWithFormat:someURL]]];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
dispatch_async(connectionQueue, ^{
[connection start]; // working fine. But WHY ????
});
Can some one please explain this weird behavior of block/GCD?
You can start a temporary NSOperationQueue for that connection. This queue will live only as long as the connection needs it. Basically the NSOperationQueue ensures that you have the delegate callbacks being queued in and processed by spinning a thread to process each delegate callback. (In most cases it is the same background thread that is put to sleep and resumed when new data is downloaded, or when connection fails, connection finishes loading etc.). Once you have this queue setup delegate callbacks will start coming into your application.
If you opt for a RunLoop instead then managing the runloop is extra burden on your part.
Try this in the first part of your code sample-
If you put the connection in a background queue, it gets shoved away after the queue is complete, and thus you don't get your delegate callbacks. The connection can be in the main queue so it stays in the main run loop for callbacks to occur. Or, you can create your own runloop that handles your background operation for you as suggested by others.
When using NSURLConnection for asynchronous communication, you need to have the thread it is instantiated in attach the connection to its RunLoop in order to have that thread poll for that same connection's delegate methods.
The proper way to instantiate a NSURLConnection asynchronously, without relying on the RunLoop of the main thread is below:
Where "theConnection" is a member variable of the current class of type "NSURLConnection". Also, you will need to create a NSOperationQueue member variable to manage the delegate callbacks once your connection receives a response. These calls will be asynchronously communicated back to the thread that is running the connection.
From there, you can return the data using the proper NSURLConnection delegate methods.
The benefit of using Grand Central Dispatch, or Operation Queues for your threads, is that the Threading and RunLoop mechanisims are already built in; You will NOT have to manually allocate an additional thread with its own RunLoop inside of it. This eliminates the two-step redundancy of creating a background-thread to manage asynchronous server calls.
I hope this is enough to get you on the right path to creating a truly asynchronous networking model for your application. :)
An NSURLConnection will always perform the fetching of data on the thread it was created on (alloc init). This explains why it would work the second way. The first way does work but the thread dies before you are able to receive any information from the NSURLConnection. NSURLConnection already allows for Asynchronous download but if you want to even run the handling of data asynchronously you should use the following method:
There are some restrictions with that method like authentication is limited and you can't track how much of the document has been downloaded to date. You must also specify an NSOperationQueue that you create, default queue being the main loop queue.