NSOperation 實現 HTTP多線程訪問
1。 從 NSOperation 派生出自己的類
#define TWITTER_URL_GET_LIST_NUMS @"http://www.xxxyyy.com/ports/miniblog/get_counts_by_account?a=%@&t=%@&f=iphone"
@protocol TwitterGetListNumsDelegate<NSObject><br />- (void) doneTwitterGetListNumbs:(NSData *) data;<br />@end</p><p>@interface TwitterGetListNumsOperation : NSOperation<br />{<br />id<TwitterGetListNumsDelegate> delegate;</p><p>NSString * nsAccount;<br />NSString * token_signature;</p><p>NSString * queryAccount;<br />}<br />@property(retain) id delegate;<br />@property(retain) NSString * nsAccount;<br />@property(retain) NSString * token_signature;<br />@property(retain) NSString * queryAccount;<br />@end<br />
@implementation TwitterGetListNumsOperation<br />@synthesize delegate;<br />@synthesize nsAccount;<br />@synthesize token_signature;<br />@synthesize queryAccount;</p><p>- (void) cleanup: (NSData*) data<br />{<br />if (self.delegate && [self.delegate respondsToSelector:@selector(doneTwitterGetListNumbs:)])<br />[self.delegate doneTwitterGetListNumbs:data];<br />}<br />- (void) main<br />{<br />NSString* token_url_encoded = URLENCODING(token_signature);<br />NSString* baseUrl = [NSString stringWithFormat:TWITTER_URL_GET_LIST_NUMS,<br /> nsAccount,token_url_encoded];</p><p>// Establish the Twitter API request<br />NSURL *url = [NSURL URLWithString:baseUrl];<br />NSLog(@"xxx - TWITTER_URL_GET_LIST_NUMS, url=%@", url);<br />NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url];</p><p>if (!urlRequest)<br />NOTIFY_AND_LEAVE(nil);//Error creating the URL Request</p><p>[urlRequest setHTTPMethod: @"POST"];<br />[urlRequest setValue:@"application/x-www-form-urlencoded"<br /> forHTTPHeaderField:@"Content-Type"];<br />[urlRequest setValue:@"XXXYYY"<br /> forHTTPHeaderField:@"X-XXXYYY-Client"];</p><p>NSString* strData = [NSString stringWithFormat:@"account=%@", queryAccount];<br />NSLog(@"xxx - strData=%@", strData);<br />NSData* postData = [strData<br />dataUsingEncoding:NSUTF8StringEncoding<br />allowLossyConversion:YES];<br />[urlRequest setHTTPBody:postData];</p><p>NSError *error;<br />NSURLResponse *response;<br />NSData *tw_result = [NSURLConnection sendSynchronousRequest:urlRequest<br /> returningResponse:&response<br /> error:&error];<br />if (!tw_result) {<br />NSString *tw_output = [NSString stringWithFormat:@"Submission error: %@",<br /> [error localizedDescription]];<br />NSLog(@"%@", tw_output);<br />NOTIFY_AND_LEAVE(nil);<br />} else {<br />//std::string output = (char*)[ bytes];<br />[self cleanup:tw_result];<br />}</p><p>}<br />@end<br />
2. 在類裡面 實現 TwitterGetListNumsDelegate, SBJsonStreamParserAdapterDelegate 兩個代理。
類裡面聲明以下變數:
SBJsonStreamParser *num_parser;
SBJsonStreamParserAdapter *num_adapter;
實現 TwitterGetListNumsDelegate 協議:
- (void) doneTwitterGetListNumbs:(NSData *) data<br />{<br />[self performSelectorOnMainThread:@selector(jsonParserFetchData:)<br /> withObject:data waitUntilDone:NO];<br />}
- (void) jsonParserFetchData : (NSData*) data<br />{<br />FLOG(@"xxx - http get lsitnums done.");<br />if(data.length == 0)<br />{<br />[num_parser release];<br />[num_adapter release];<br />num_parser = nil;<br />num_adapter = nil;</p><p>return;<br />}</p><p>// Parse the new chunk of data. The parser will append it to<br />// its internal buffer, then parse from where it left off in<br />// the last chunk.</p><p>std::string a = (char*)[data bytes];<br />LOG(LS_VERBOSE)<<a;</p><p>SBJsonStreamParserStatus status = [num_parser parse:data];</p><p>if (status == SBJsonStreamParserError)<br />{<br />NSLog(@"Parser error: %@", num_parser.error);<br />} else if (status == SBJsonStreamParserWaitingForData)<br />{<br />NSLog(@"Parser waiting for more data");<br />}</p><p>[num_parser release];<br />[num_adapter release];<br />num_parser = nil;<br />num_adapter = nil;<br />}<br />
在這個函數裡面,調用JSON PARSER 去解析結果。
下面是 實現 JSON PArser 協議:
- (void)parser:(SBJsonStreamParser *)parser foundArray:(NSArray *)array<br />{<br />NSLog(@"ArrayTweet: '%@'", array);<br />}
- (void)parser:(SBJsonStreamParser *)parser foundObject:(NSDictionary *)dict<br />{<br />//獲得列表數量<br />if (parser==num_parser)<br />{<br />NSNumber *result = [dict objectForKey:@"result"];<br />FLOG(@"xxx - SBJsonStreamParser result: '%d'", [result intValue]);<br />if ([result intValue])<br />{<br />NSDictionary *data = [dict objectForKey:@"data"];</p><p>NSLog(@"xxx - tableView reloadData", data);</p><p>NSNumber* BlogNum= [data objectForKey:@"blog_num"];<br />NSNumber* FollowNum=[data objectForKey:@"follow_num"];<br />NSNumber* FansNum=[data objectForKey:@"fans_num"];</p><p>NSString *strBlogNum=[[BlogNum stringValue] UTF8String];<br />NSString *strFollowNum=[[FollowNum stringValue] UTF8String];<br />NSString *strFansNum=[[FansNum stringValue] UTF8String];<br />}</p><p>}<br />}
3. 如何調用這個呢?
- (void) getListNum<br />{<br />num_adapter = [SBJsonStreamParserAdapter new];<br />num_adapter.delegate = self;<br />num_parser = [SBJsonStreamParser new];<br />num_parser.delegate = num_adapter;<br />num_parser.multi = YES;</p><p>std::string username = @"";<br />std::string token_signature = @"";</p><p>TwitterGetListNumsOperation *operation = [[[TwitterGetListNumsOperation alloc] init] autorelease];<br />operation.delegate = self;<br />operation.nsAccount = [NSString stringWithCString:username.c_str()<br /> encoding:NSUTF8StringEncoding];<br />operation.token_signature = [NSString stringWithCString:token_signature.c_str()<br /> encoding:NSUTF8StringEncoding];</p><p>operation.queryAccount= [NSString stringWithCString:twitter_item_.account.c_str() encoding:NSUTF8StringEncoding];</p><p>NSOperationQueue *queue = [[[NSOperationQueue alloc] init] autorelease];<br />[queue addOperation:operation];<br />}<br />
如果有多個類型的NSOperation同時在一個類中進行,就建立多個 adapter和 parser,通過這個來判斷是那個Operation的結果。而且由於
是多線程,所以在返回結果的時候,可能會導致crash,採取的辦法是,等一個HTTP Operation操作結果返回以後,再進行下一個HTTP Opeation操作。