Friday, August 13, 2010

Asynchronous data request class

A very handly class I've built is asyncDataRequest. This provides for an easy way to make and receive calls to web data feeds. All you have to do is include the class reference in your .m file, make the request and create a notification responder to receive and parse that data response.

First, we'll look at asyncDataRequest.h:
@interface asyncDataRequest : NSObject {
 NSMutableData *responseData;
 id delegate;
 NSString *notificationName;
}

@property(nonatomic,retain) NSMutableData *responseData;
@property(nonatomic,assign) id delegate;
@property(nonatomic,retain) NSString *notificationName;

- (void)setDelegate:(id)newDelegate;
- (void)connection:(NSURLConnection *)connection didReceiveResponse: (NSURLResponse *)response;
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data;
- (void)connection:(NSURLConnection *)connection didFailWithError: (NSError *)error;
- (void)connectionDidFinishLoading: (NSURLConnection *)connection;

@end



The code for asyncDataRequest.m is:
#import "asyncDataRequest.h"


@implementation asyncDataRequest
@synthesize responseData, delegate, notificationName;
- (id)delegate {
 return delegate;
}

- (void)setDelegate:(id)newDelegate {
 delegate = newDelegate;
}

- (void)connection:(NSURLConnection *)connection didReceiveResponse: (NSURLResponse *)response {
 [self.responseData setLength:0];
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
 // Process the downloaded chunk of data.
 [self.responseData appendData:data];
 spLog(@"data: %i", [self.responseData length]);
 
}

- (void) connectionDidFinishLoading: (NSURLConnection *)connection {
 spLog(@"finished");
 
 NSString *asyncReturn = [[NSString alloc] initWithData:self.responseData encoding:NSUTF8StringEncoding];
 if(asyncReturn != NULL) {
  spLog(@"asyncReturn: %@", asyncReturn);
  if([asyncReturn isEqualToString:@"FALSE"] || [asyncReturn hasPrefix:@"ERROR"] || asyncReturn == nil || [[asyncReturn stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] hasPrefix:@"<"] && ![[asyncReturn stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] hasPrefix:@"<form"]) {
   NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
   [dict setObject:[NSNumber numberWithBool:YES] forKey:@"isError"];
   [dict setObject:[NSString stringWithString:@""] forKey:@"response"];
   [[NSNotificationCenter defaultCenter] postNotificationName:self.notificationName object:self userInfo:dict];
   [dict release];
  } else {
   NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
   [dict setObject:[NSNumber numberWithBool:NO] forKey:@"isError"];
   [dict setObject:[NSString stringWithString:asyncReturn] forKey:@"response"];
   [[NSNotificationCenter defaultCenter] postNotificationName:self.notificationName object:self userInfo:dict];
   [dict release];
  }
 }
 [asyncReturn release];
 [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
 
 NSURLCache *sharedCache = [[NSURLCache alloc] initWithMemoryCapacity:0 diskCapacity:0 diskPath:nil];
 [NSURLCache setSharedURLCache:sharedCache];
 [sharedCache release];
 
}

- (void) connection:(NSURLConnection *)connection didFailWithError: (NSError *)error {
 spLog(@"error");
 [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
 NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
 [dict setObject:[NSNumber numberWithBool:YES] forKey:@"isError"];
 [dict setObject:[NSString stringWithString:@""] forKey:@"response"];
 [[NSNotificationCenter defaultCenter] postNotificationName:self.notificationName object:self userInfo:dict];
 [dict release];
 
}

- (void)dealloc {
 [self.responseData release];
 [self.notificationName release];
 [super dealloc];
}

@end

In order to implement this method:
NSURL *sURL = [[NSURL alloc] initWithString:urlString];
  
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:sURL];
//create delegate instance
asyncDataRequest *adr = [[asyncDataRequest alloc] init];
adr.notificationName = @"ASYNC_RESPONSE_NOTIFICATION";
[adr setDelegate:self];
  
NSURLConnection *connectionADR = [[NSURLConnection alloc] initWithRequest:request delegate:adr];
if(connectionADR) {
 adr.responseData = [[NSMutableData data] retain];
 [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
} else {
 //connection error
 spLog(@"connection error");
}
[connectionADR release];
[adr release];
[sURL release];
[request release];

You'll also need a notification handler (since this asynchronous after all).
// Add the notification observer in viewDidLoad
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(returnFromAsyncNotification:) name:@"ASYNC_RESPONSE_NOTIFICATION" object:nil];

- (void)returnFromAsyncNotification:(NSNotification *)notify {
 id ndict = [notify userInfo];
 BOOL isError = [[ndict objectForKey:@"isError"] boolValue];
 NSString *strResponse = [ndict objectForKey:@"response"];
 spLog(@"strResponse: %@", strResponse);
 if(isError) {
  // Handle connection error
 } else {
  // Do something with returned data string, strResponse
 }
}

And there you have it. Enjoy!

No comments:

Post a Comment