2012-03-11 43 views
2

我需要製作多個NSURLConnections到JSON Web服務。我希望每個WS調用都保持UI通知,可能帶有UIActivityIndi​​catorView和標籤。到目前爲止,我創建了一個NSURLConnection helper類來處理連接,並將URL委託放入View中。這對於通過單個WS調用來更新UI非常有用。iOS 5與NSOperationQueue的NSURLConnection - 提供UI反饋

對於多個調用,我試圖使用一個NSOperationQueue。我想將MaxConcurrentOperationCount設置爲隊列中的一個,以便每次操作一次執行一個操作。這裏有我的視圖控制器相關代碼:

ViewController.m

#import "URLOperationHelper.h" 

@implementation ViewController 

- (IBAction)showPopup:(id)sender 
{ 
    // Dictonary holds POST values 
    NSMutableDictionary *reqDic = [NSMutableDictionary dictionary]; 

    // Populate POST key/value pairs 
    [reqDic setObject:@"pw" forKey:@"Password"]; 
    [reqDic setObject:@"ur" forKey:@"UserName"]; 

    operationQueue = [[NSOperationQueue alloc] init]; 
    [operationQueue setMaxConcurrentOperationCount:1]; 
    [operationQueue cancelAllOperations]; 
    [operationQueue setSuspended:YES];  

    URLOperationHelper *wsCall1 = [[URLOperationHelper alloc] initWithURL:@"urlString1" postParameters:reqDic urlDelegate:self]; 

    URLOperationHelper *wsCall2 = [[URLOperationHelper alloc] initWithURL:@"urlString2" postParameters:reqDic urlDelegate:self]; 

    [operationQueue addOperation:wsCall1]; 
    [operationQueue addOperation:wsCall2];   

} 

// Did the URL Connection receive a response 
-(void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response 
{ 
    NSLog(@"Did receive response: %@", response); 

    NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response; 
    int code = [httpResponse statusCode]; 

    // Handle status code here 

    webData = [[NSMutableData alloc]init]; 
} 

// Did the URL Connection receive data 
-(void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data 
{ 
    NSLog(@"Did receive data: %@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]); 

    assert(webData != nil); 
    [webData appendData:data]; 
} 

// Did the connection fail with an error? 
-(void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error 
{ 
    NSLog(@"%@", error); 
} 

// Executes after a successful connection and data download 
-(void) connectionDidFinishLoading:(NSURLConnection *)connection 
{ 
    NSLog(@"Connection finished"); 
} 

@end 

這裏是我的URLOperationHelper.m

@implementation URLHelper 
    - (id)initWithURL:(NSString *)urlPath 
     postParameters:(NSMutableDictionary *)postParameters 
    urlParentDelegate:(id) pDelegate 
    { 
     if(self = [super init]) 
     { 
      connectionURL = urlPath; 
      postParams = postParameters; 
      parentDelegate = pDelegate; 
     } 

     return self; 
    } 

    - (void)done 
    { 
     // Cancel the connection if present 
     if(urlConnection) 
     { 
      [urlConnection cancel]; 
      urlConnection = nil; 
     } 

     // Alert 
     [self willChangeValueForKey:@"isExecuting"]; 
     [self willChangeValueForKey:@"isFinished"]; 

     executing = NO; 
     finished = YES; 

     [self willChangeValueForKey:@"isFinished"]; 
     [self willChangeValueForKey:@"isExecuting"]; 
    } 

    - (void)cancel 
    { 
     // Possibly add an NSError Property 
     [self done]; 
    } 

    - (void)start 
    { 
     // Make sure this operation starts on the main thread 
     if(![NSThread isMainThread]) 
     { 
      [self performSelectorOnMainThread:@selector(start) withObject:nil waitUntilDone:NO]; 
      return; 
     } 

     // Make sure that the operation executes 
     if(finished || [self isCancelled]) 
     { 
      [self done]; 
      return; 
     } 

     [self willChangeValueForKey:@"isExecuting"]; 
     executing = YES; 

     [self main]; 
     [self willChangeValueForKey:@"isExecuting"]; 
    } 

    - (void)main 
    { 
     NSError *error = nil; 
     NSData *jsonData = [NSJSONSerialization dataWithJSONObject:postParams options:NSJSONWritingPrettyPrinted error:&error]; 

     // Convert dictionary to JSON 
     NSString *requestJSON = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; 

     NSLog(@"JSONRequest: %@", requestJSON); 

     // Declare Webservice URL, request, and return data 
     url = [[NSURL alloc] initWithString:connectionURL]; 
     NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url]; 
     NSData *requestData = [NSData dataWithBytes:[requestJSON UTF8String] length:[requestJSON length]]; 

     // Build the request 
     [request setHTTPMethod:@"POST"]; 
     [request setValue:[NSString stringWithFormat:@"%d", [requestData length]] forHTTPHeaderField:@"Content-Length"]; 
     [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; 
     [request setHTTPBody:requestData]; 

     // Connect to Webservice 
     // Responses are handled in the delegates below 
     urlConnection = [[NSURLConnection alloc] initWithRequest:request delegate:parentDelegate startImmediately:YES]; 
    } 

    - (BOOL)isConcurrent 
    { 
     return YES; 
    } 

    - (BOOL)isExecuting 
    { 
     return executing; 
    } 

    -(BOOL)isFinished 
    { 
     return finished; 
    } 

    @end 

說我遇到的問題是在從不調用URLOperation的啓動方法。 OperationQueue被創建並且操作被調用,但是在那之後,執行或者線程明智之後什麼也沒有發生。

此外,這是一個正確的思路,用這種NSOperationQueues提供UI反饋? I.E.從Operation中調用NSURLDelegates?

回答

3

如果添加操作,那麼你的操作之前設置setSuspendedYES將排隊進入暫停隊列..我建議不要在

而且暫停隊列,您的操作永遠不會結束呢。您需要將操作本身分配爲委託並實施所有必要的委託方法。在這些方法中,你可以將郵件轉發到您的parentDelegate,並決定何時完成,並打電話給你做的方法在適當的時候(我建議connection:didFailWithError:connectionDidFinishLoading:

有一個很好的教程在這裏:http://blog.9mmedia.com/?p=549

你也沒有完全實現正確的鍵值編碼compilant屬性。每當你打電話willChangeValueForKey:你還需要調用didChangeValueForKey算賬:

- (void)start 
{ 
    ... 
    [self willChangeValueForKey:@"isExecuting"]; 
    executing = YES; 
    [self didChangeValueForKey:@"isExecuting"]; 

    [self main]; 
} 

和:

- (void)done 
{ 
    ... 

    // Alert 
    [self willChangeValueForKey:@"isExecuting"]; 
    [self willChangeValueForKey:@"isFinished"]; 

    executing = NO; 
    finished = YES; 

    [self didChangeValueForKey:@"isFinished"]; 
    [self didChangeValueForKey:@"isExecuting"]; 
} 

看到這個Q/A的KVC:when to use "willChangeValueForKey" and "didChangeValueForKey"?

+0

我註釋掉線和第一操作執行。但是,第二個操作從未開始。任何想法爲什麼? – Joshua 2012-03-11 18:24:19

+0

編輯。你需要改變你的操作方式 – 2012-03-11 19:53:41

+0

好吧,我通過向連接添加了[self done]來完成更新:didFailWithError和connectionDidFinishLoading :.這是一些很好的反饋。不過,我只能將第一個操作添加到隊列中執行。是因爲我有[operationQueue setMaxConcurrentOperationCount:1];? – Joshua 2012-03-11 20:59:42