2013-12-23 36 views
4

我正在調用一個枚舉整個數組,創建NSURL並調用返回JSON的NSURLSessionDataTask的方法。該循環通常運行約10次,但可以根據當天而變化。如何知道何時使用NSURLSessionDataTasks的for循環完成

我需要等待for循環和所有NSURLSessionDataTasks才能開始處理數據。

我很難搞清楚什麼時候所有的工作都完成了。任何人都可以推薦任何方式或邏輯來了解整個方法何時完成(用於循環和數據任務)?

-(void)findStationsByRoute{ 
for (NSString *stopID in self.allRoutes) { 
    NSString *urlString =[NSString stringWithFormat:@"http://truetime.csta.com/developer/api/v1/stopsbyroute?route=%@", stopID]; 
    NSURL *url = [NSURL URLWithString:urlString]; 
    NSURLRequest *request = [NSURLRequest requestWithURL:url]; 
    NSURLSessionDataTask *task = [self.session dataTaskWithRequest:request 
               completionHandler:^(NSData *data, 
                    NSURLResponse *response, 
                    NSError *error) { 
                NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; 
                if(httpResponse.statusCode == 200){ 
                 NSError *jsonError = [[NSError alloc]init]; 
                 NSDictionary *stopLocationDictionary = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&jsonError]; 
                 NSArray *stopDirectionArray = [stopLocationDictionary objectForKey:@"direction"]; 
                 for (NSDictionary * _stopDictionary in stopDirectionArray) { 
                  NSArray *stop = [_stopDictionary objectForKey:@"stop"]; 
                  [self.arrayOfStops addObject:stop]; 

                 } 
                } 

               }]; 

    [task resume]; 
} 

}

+0

你的任務在completionHandler塊中完成。 – johnMa

回答

5

有多種選擇。根本問題是這些單獨的數據任務是異步運行的,所以您需要一些方法來跟蹤這些異步任務並確定它們完成時的依賴關係。

有幾種可能的方法:

  1. 典型的解決方案是採用一個調度組。在使用dispatch_group_enter開始請求之前輸入組,並在完成處理程序中將dispatch_group_leave保留在異步調用中,然後在循環結束時提供一個dispatch_group_notify塊,當所有「回車離開‘」電話被相應的補償’要求:

    - (void)findStationsByRoute { 
        dispatch_group_t group = dispatch_group_create(); 
    
        for (NSString *stopID in self.allRoutes) { 
         NSString  *urlString = [NSString stringWithFormat:@"http://truetime.csta.com/developer/api/v1/stopsbyroute?route=%@", stopID]; 
         NSURL  *url  = [NSURL URLWithString:urlString]; 
         NSURLRequest *request = [NSURLRequest requestWithURL:url]; 
    
         dispatch_group_enter(group); // enter group before making request 
    
         NSURLSessionDataTask *task = [self.session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { 
          NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; 
          if(httpResponse.statusCode == 200){ 
           NSError *jsonError; // Note, do not initialize this with [[NSError alloc]init]; 
           NSDictionary *stopLocationDictionary = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError]; 
           NSArray *stopDirectionArray = [stopLocationDictionary objectForKey:@"direction"]; 
           for (NSDictionary *stopDictionary in stopDirectionArray) { 
            NSArray *stop = [stopDictionary objectForKey:@"stop"]; 
            [self.arrayOfStops addObject:stop]; 
           } 
          } 
    
          dispatch_group_leave(group); // leave group from within the completion handler 
         }]; 
    
         [task resume]; 
        } 
    
        dispatch_group_notify(group, dispatch_get_main_queue(), ^{ 
         // do something when they're all done 
        }); 
    } 
    
  2. 更復雜的方式來處理,這是包裝的NSSessionDataTaskNSOperation子類,然後你可以將數據任務操作和最終之間使用的依賴完成操作。您需要確保您的單個數據任務操作是「併發」操作(即在異步數據任務完成之前不要發出isFinished通知)。這種方法的好處是您可以設置maxConcurrentOperationCount來約束在任何給定時間將啓動多少個請求。一般來說,你想一次限制到3-4個請求。

    注意,這也可以解決調度組方法可能遭受的超時問題。調度組不限制在任何給定時間提交的請求數量,而使用NSOperation可以輕鬆完成。

    有關詳細信息,請參閱併發編程指南的Operation Queue部分中關於「併發操作」的討論。

    用於包裹在異步NSOperation子類NSURLSessionTask請求的一個例子,請參閱一個簡單的實現後半部分NSURLSession with NSBlockOperation and queues。這個問題正在解決一個不同的話題,但最後我還包括了一個NSOperation子類示例。

  3. 如果不是數據任務,您使用的上傳/下載任務,然後你可以使用一個[NSURLSessionConfiguration backgroundSessionConfiguration]和您NSURLSessionDelegate隨後將被調用URLSessionDidFinishEventsForBackgroundURLSession:當所有的任務都做了和應用程序被帶回到前臺。(有點令人討厭的是,只有在下載完成時你的應用程序沒有被激活時纔會被調用:我希望這個代理方法被重新調用,即使應用程序在下載完成時位於前臺也是如此。)

    當您詢問有關數據任務(不能與後臺會話一起使用)時,使用帶有上傳/下載任務的後臺會話享有後臺操作的顯着優勢。如果你的過程真的需要10分鐘(這看起來非同尋常),重構這個背景會話可能會提供顯着的優勢。

  4. 我討厭甚至提到這一點,但爲了完整起見,我應該承認,理論上你可以通過維護一個可變數組或字典的待處理數據任務,並在完成每個數據任務後,來自該列表的項目,並且如果它結束它是最後的任務,則手動啓動完成過程。

3

dispatch groups,你比如它看起來大致是這樣的:

create group 
for (url in urls) 
    enter group 
    start_async_task 
     when complete leave group 

wait on group to finish or supply a block to be run when completed 
+2

順便說一句,如果你使用這種技術,確保你的任務是同步的(例如使用信號量),否則你的組將在所有任務排隊後「完成」,而不是當所有任務完成時。 – Rob