NSURLConnection和大中央调度
build议在gcd样式块中包装NSUrlConnection并在low_priority队列上运行它?
我需要确保我的连接没有发生在主线程上,连接需要是asynchronous的。 我还需要同时发出几个请求。
如果我去gcd路线,我不知道哪个线程的NSUrlConnectionDelegate方法被调用。
NSURLConnection依赖委托,所以一旦连接完成,无论处理它的包装类将需要调用其调用者。 我不确定如何处理连接工作启动/结束时调用的所有各种callback:
- (void)connection:(NSURLConnection *)aConnection didReceiveResponse:(NSURLResponse *)response; - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)incrementalData; - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error; - (void)connectionDidFinishLoading:(NSURLConnection *)connection;
我应该只是调用同步版本,但包裹在gcd块? 如果我想取消呼叫,请使用'dispatch_suspend'?
dispatch_async(queue,^{ NSString* result = [self mySynchronousHttp:someURLToInvoke]; }); // If I need to cancel dispatch_suspend(queue);
我build议您在iPhone OS中查看关于networking应用程序的WWDC会话。
- WWDC 2010 Session 207 – iPhone OS的networking应用程序,第1部分
- WWDC 2010 Session 208 – iPhone OS的networking应用程序,第2部分
讲师说
“线程是邪恶的”
进行networking编程,build议使用RunLoop进行asynchronousnetworking编程。 使用后台线程(Grand Central Dispatch Concurrent Queue)进行线程安全数据处理,而不是用于networking编程。
顺便说一下,块和大中央调度会议也值得一看。
- WWDC 2010第206期 – 在iPhone中引入Blocks和Grand Central Dispatch
- WWDC 2010第211课 – 通过Grand Central Dispatch简化iPhone应用程序开发
我为asynchronousNSURLConnection编写了一个包装类。
AsyncURLConnection.h
#import <Foundation/Foundation.h> typedef void (^completeBlock_t)(NSData *data); typedef void (^errorBlock_t)(NSError *error); @interface AsyncURLConnection : NSObject { NSMutableData *data_; completeBlock_t completeBlock_; errorBlock_t errorBlock_; } + (id)request:(NSString *)requestUrl completeBlock:(completeBlock_t)completeBlock errorBlock:(errorBlock_t)errorBlock; - (id)initWithRequest:(NSString *)requestUrl completeBlock:(completeBlock_t)completeBlock errorBlock:(errorBlock_t)errorBlock; @end
AsyncURLConnection.m
#import "AsyncURLConnection.h" @implementation AsyncURLConnection + (id)request:(NSString *)requestUrl completeBlock:(completeBlock_t)completeBlock errorBlock:(errorBlock_t)errorBlock { return [[[self alloc] initWithRequest:requestUrl completeBlock:completeBlock errorBlock:errorBlock] autorelease]; } - (id)initWithRequest:(NSString *)requestUrl completeBlock:(completeBlock_t)completeBlock errorBlock:(errorBlock_t)errorBlock { if ((self=[super init])) { data_ = [[NSMutableData alloc] init]; completeBlock_ = [completeBlock copy]; errorBlock_ = [errorBlock copy]; NSURL *url = [NSURL URLWithString:requestUrl]; NSURLRequest *request = [NSURLRequest requestWithURL:url]; [NSURLConnection connectionWithRequest:request delegate:self]; } return self; } - (void)dealloc { [data_ release]; [completeBlock_ release]; [errorBlock_ release]; [super dealloc]; } - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { [data_ setLength:0]; } - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { [data_ appendData:data]; } - (void)connectionDidFinishLoading:(NSURLConnection *)connection { completeBlock_(data_); } - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { errorBlock_(error); } @end
如何使用AsyncURLConnection类。
/* * AsyncURLConnection -request:completeBlock:errorBlock: have to be called * from Main Thread because it is required to use asynchronous API with RunLoop. */ [AsyncURLConnection request:url completeBlock:^(NSData *data) { /* success! */ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ /* process downloaded data in Concurrent Queue */ dispatch_async(dispatch_get_main_queue(), ^{ /* update UI on Main Thread */ }); }); } errorBlock:^(NSError *error) { /* error! */ }];
创build一个在其上运行asynchronousNSURLConnection的并发NSOperation。
看看这个代码块:
-(void)getDataFromServer { NSDictionary *dicParams = [NSDictionary dictionaryWithObjectsAndKeys: userId, kUserID, pageIndex,kPageIndex, nil]; NSString *yourURL = [self addQueryStringToUrlString:[NSString stringWithFormat:@"%@/%@",_PATH_,apiName] withDictionary:dicParams]; NSString *queue_id = @"_queue_id_"; dispatch_queue_t queue = dispatch_queue_create([queue_id UTF8String], 0); dispatch_queue_t main = dispatch_get_main_queue(); dispatch_async(queue, ^{ NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:yourURL] cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:60.0]; [theRequest setHTTPMethod:@"GET"]; [theRequest setValue:@"application/json" forHTTPHeaderField:@"Accept"]; [theRequest setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; NSError *serviceError = nil; NSURLResponse *serviceResponse = nil; NSData *dataResponse = [NSURLConnection sendSynchronousRequest:theRequest returningResponse:&serviceResponse error:&serviceError]; if(serviceError) { dispatch_sync(main, ^{ // Update your UI if(serviceError.code == -1012){ // Log error }else{ // Log error } }); } else { NSError *jsonError = nil; id dataObject = [NSJSONSerialization JSONObjectWithData:dataResponse options:kNilOptions error:&jsonError]; NSMutableArray *arrResponse = (NSMutableArray *)dataObject; dispatch_sync(main, ^{ // Update your UI [yourTableView reloadData]; }); } }); } +(NSString*)addQueryStringToUrlString:(NSString *)urlString withDictionary:(NSDictionary *)dictionary { NSMutableString *urlWithQuerystring = [[NSMutableString alloc] initWithString:urlString]; for (id key in dictionary) { NSString *keyString = [key description]; NSString *valueString = [[dictionary objectForKey:key] description]; if ([urlWithQuerystring rangeOfString:@"?"].location == NSNotFound) { [urlWithQuerystring appendFormat:@"?%@=%@", [self urlEscapeString:keyString], [self urlEscapeString:valueString]]; } else { [urlWithQuerystring appendFormat:@"&%@=%@", [self urlEscapeString:keyString], [self urlEscapeString:valueString]]; } } return urlWithQuerystring; } +(NSString*)urlEscapeString:(NSString *)unencodedString { CFStringRef originalStringRef = (__bridge_retained CFStringRef)unencodedString; NSString *s = (__bridge_transfer NSString *)CFURLCreateStringByAddingPercentEscapes(NULL,originalStringRef, NULL, NULL,kCFStringEncodingUTF8); CFRelease(originalStringRef); return s; }