01 October 2011

Centralize your NSURLConnection code while using Async connections

We should use Aysnc calls when dealing with NSURLConnections. May articles illustrate why we should do that, among them is this one The truth about synchronous NSURLConnection. Also see my question on SO. But We want also to have our "Communicate" code grouped somewhere not to be implemented by all of our classes in the project. This post is talking about how to solve this issue.. Thanks to AliSoftware . Well, We will have some Utility class the doing the connection and handle the data for us.. but what will we do when we got the data from the server? we should call some method on the caller class (in cases, it is a ViewContoller).. so we should send the target class and the selector to be called when the connection done receiving data. So, Here's the code (quick and dirty) for the URLCaller class:
  1. 
  2. #import <Foundation/Foundation.h>
  3. 
  4. @interface URLCaller : NSObject
  5. {
  6.     NSMutableData* data;
  7.     NSObject* target;
  8.     SEL selector;
  9. }
 10. @property (nonatomic, retain) NSMutableData* data;
 11. @property (nonatomic, retain) NSObject* target;
 12. @property (nonatomic) SEL selector;
 13. 
 14. -(id) initWithTarget:(NSObject*) target selector:(SEL)selector;
 15. -(void) call:(NSString*) url;
 16. 
 17. @end
 18. 
 19. 
 20. #import "URLCaller.h"
 21. 
 22. @implementation URLCaller
 23. @synthesize data, target, selector;
 24. 
 25. -(id) initWithTarget:(NSObject*) _target selector:(SEL)_selector
 26. {
 27.     if (self = [super init])
 28.     {
 29.         self.target = _target;
 30.         self.selector = _selector;
 31.     }
 32.     return self;
 33. }
 34. 
 35. -(void) call:(NSString*) url
 36. {
 37.     NSURLConnection* connection = [[NSURLConnection alloc]initWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:url]] delegate:self];
 38.     [connection release];
 39. }
 40. 
 41. #pragma mark - NSURLConnection deleages
 42. 
 43. -(void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)response
 44. {
 45.     data = [[NSMutableData alloc] init]; // _data being an ivar
 46. }
 47. -(void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)_data
 48. {
 49.     [self.data appendData:_data];
 50. }
 51. -(void)connection:(NSURLConnection*)connection didFailWithError:(NSError*)error
 52. {
 53.     // Handle the error properly
 54. }
 55. -(void)connectionDidFinishLoading:(NSURLConnection*)connection
 56. {
 57.     NSString* stringData = [[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]autorelease];
 58.     [target performSelector:selector withObject:stringData];
 59. }
 60. 
 61. - (void)dealloc 
 62. {
 63.     [target release];
 64.     [data release];
 65.     [super dealloc];
 66. }
 67. 
 68. @end
And in the caller class (in my case is a ViewController), we will use the URLCaller class:
  1. 
  2. -(IBAction)getDataFromServer:(id)sender
  3. {
  4.     URLCaller* caller = [[URLCaller alloc]initWithTarget:self selector:@selector(setTextViewContents:)];
  5.     [caller call:@"http://search.twitter.com/search.json?q=Muhammad"];
  6.     [caller release];
  7. }
  8. 
  9. // this will got called when the data returned from the server
 10. -(void) setTextViewContents:(NSString*) contents
 11. {
 12.     text.text = contents;
 13. }
You can get the project source code from here Very important notice is that, the application will never got freeze while the data is being transferred, and this is what we wants!

No comments: