I'm currently using synchronous ASIHTTPRequest with GCD queues to download data from the Internet, then parse the response data with JSONKit. What do you think about this pattern. Thank you in advance.
Here is my code:
dispatch_async(queue, ^(void) {
// Request is ASIHTTPRequest.
[request startSynchronous];
// Parse JSON.
NSArray *array = [[request responseData] objectFromJSONDataWithParseOptions:JKParseOptionLooseUnicode];
// Callback on the main queue to update UI.
dispatch_async(dispatch_get_main_queue(), ^(void) {
callbackBlock(array);
});
});
EDIT: The reason I use ASIHTTPRequest is that I need to modify the request header for OAuth and use POST method to upload images.
So you replaced this
- (void)doDownload {
NSURL *url = [NSURL URLWithString:@"http://foobar.com"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
connection = [[NSURLConnection alloc] initWithRequest:aURLRequest delegate:self];
receivedData = [[NSMutableData data] retain];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[_receivedData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSArray *array = [_receivedData objectFromJSONDataWithParseOptions:JKParseOptionLooseUnicode];
callbackBlock(array);
}
with this -
- (void)doDownload {
NSURL *url = [NSURL URLWithString:@"http://foobar.com"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^(void) {
[request startSynchronous];
NSArray *array = [[request responseData] objectFromJSONDataWithParseOptions:JKParseOptionLooseUnicode];
// Callback on the main queue to update UI.
dispatch_async(dispatch_get_main_queue(), ^(void) {
callbackBlock(array);
});
});
}
and 10,000+ lines of code from ASIHTTPRequest.
What has it got you?
NSURLConnection is fully asynchronous, uses GCD, caches, automatic zip/unzip, etc, etc..
For that reason, and going solely on the (possibly incomplete) information you provided, i'd say that it was a really awful piece of code.
Of course, context is everything - and you may have a really, really, really good reason for reimplementing the already existing functionality of Library code provided by Apple.
At WWDC2010, for network programming, Apple recommends to use asynchronous programming with RunLoop.
- WWDC 2010 Session 207 - Network Apps for iPhone OS, Part 1
- WWDC 2010 Session 208 - Network Apps for iPhone OS, Part 2
NSURLConnection asynchronous request is one of the most efficient way. But if you want to use ASIHTTPRequest, how about it? (ASIHTTPRequest asynchronous request is implemented using NSOperationQueue, it is not same as NSURLConnection asynchronous.)
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setCompletionBlock:^{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
NSData *responseData = [request responseData];
/* Parse JSON, ... */
dispatch_async(dispatch_get_main_queue(), ^{
callbackBlock(array);
});
});
}];
[request setFailedBlock:^{
NSError *error = [request error];
/* error handling */
}];
[request startAsynchronous];
That code looks ok for a single network connection, but if you are using ASIHTTPRequest you will likely be a mobile application. For multiple concurrent downloads I would implement a queue (see "Using a queue" in the ASIHTTPRequest docs) where you can specify the amount of maximum simultaneous connections (say use 2 on GPRS and 8 on wifi) or throttle the bandwidth. Then, in the finish selector use GDC or something else to run the processing of the data out of the main UI thread.
In essence, using blocks with ASIHTTPRequest for the simple case only brings you a different syntax with regards to NSURLConnection, as fakeAccount22 mentioned. And NSURLConnection also has synchronous methods, so you can avoid an external dependency (and potential source of bugs/problems) and use that in blocks.
Best way to do it is to use gcd when getting the callback and not when initiating the request. Then you could parse on background thread and notifiy on main thread. Good luck!