2013-12-21 46 views
1

我的假設是operation在一個單獨的線程上異步運行,但循環不會退出,所以某些事情並不如我所設想的那樣。爲什麼這個循環不會退出

/** 
Checks if we can communicate with the APIs 

@result YES if the network is available and all of the registered APIs are responsive 
*/ 
- (BOOL)apisAvailable 
{ 
    // Check network reachability 
    if (!_connectionAvailable) { 
     return NO; 
    } 
    // Check API server response 
    NSMutableSet *activeOperations = [[NSMutableSet alloc] init]; 
    __block NSInteger successfulRequests = 0; 
    __block NSInteger failedRequests = 0; 
    for (AFHTTPClient *httpClient in _httpClients) { 
     // Send heart beat request 
     NSMutableURLRequest *request = [httpClient requestWithMethod:@"GET" path:@"" parameters:nil]; 
     AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request]; 
     [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { 
      // Server returned good response 
      successfulRequests += 1; 
     } failure:^(AFHTTPRequestOperation *operation, NSError *error) { 
      // Server returned bad response 
      failedRequests += 1; 
     }]; 
     [operation start]; 
     [activeOperations addObject:operation]; 
    } 
    // Wait for heart beat requests to finish 
    while (_httpClients.count > (successfulRequests + failedRequests)) { 
     // Wait for each operation to finish, one at a time 
     //usleep(150); 
     [NSThread sleepForTimeInterval:0.150]; 
    } 
    // Check final results 
    if (failedRequests > 0) { 
     return NO; 
    } 
    return YES; 
} 
+0

回答我的問題,但我會等待更多的反饋,我纔回答它。 – Brenden

回答

0

我相信問題是我沒有使用鎖定來增加計數器,所以while循環永遠不會計算到true

只要找到大於0的故障計數,只要它被任何請求回調模塊增加,我就能得到它的工作,然後我知道該怎麼做。

我只是碰巧已經切換到[NSOperationQueue waitUntilAllOperationsAreFinished]

最終代碼:

/** 
Checks if we can communicate with the APIs 

@result YES if the network is available and all of the registered APIs are responsive 
*/ 
- (BOOL)apisAvailable 
{ 
    // Check network reachability 
    if (!_connectionAvailable) { 
     return NO; 
    } 
    // Check API server response 
    NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init]; 
    __block NSInteger failedRequests = 0; 
    for (AFHTTPClient *httpClient in _httpClients) { 
     // Send heart beat request 
     NSMutableURLRequest *request = [httpClient requestWithMethod:@"GET" path:@"" parameters:nil]; 
     AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request]; 
     [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { 
      // Server returned good response 
     } failure:^(AFHTTPRequestOperation *operation, NSError *error) { 
      // Server returned bad response 
      failedRequests += 1; 
     }]; 
     [operationQueue addOperation:operation]; 
    } 
    // Wait for heart beat requests to finish 
    [operationQueue waitUntilAllOperationsAreFinished]; 
    // Check final results 
    if (failedRequests > 0) { 
     return NO; 
    } 
    return YES; 
} 
2

幾點建議:

  • 從不檢查可達性,以確定是否一個請求會成功。你應該嘗試這個請求;只有在它失敗的情況下,你應該詢問可達性來嘗試並得出最佳猜測。可達性使沒有保證請求是否會失敗或成功。

  • 此方法在主線程上調用嗎?即使您解決了永不完成請求的問題,它也會在網絡請求運行的整個過程中阻止用戶界面。由於這些請求可能需要很長時間,因此對於用戶來說這是一種糟糕的體驗,以及操作系統會在錯誤的時間(例如,啓動時)將您的應用程序殺死的情況。

  • 在調用睡眠或等效函數時循環會浪費CPU資源和內存,並阻止線程的runloop服務任何定時器,事件處理程序或回調。 (這可能是爲什麼網絡完成塊永遠不能運行。)如果你可以避免阻塞一個線程,你應該。另外,如果你在沒有自己創建的NSThread上做這件事,Cocoa通常會很不高興。

我看到兩個選項:

  1. 使用dispatch_group s到等待所有請求完成的。不要阻止你的調用線程,而應該在完成時調用完成塊來調用。所以,不要返回一個BOOL,而要帶一個BOOL的完成塊。像- (void)determineIfAPIIsAvailable:(void(^)(BOOL))completionBlock;

  2. 完全擺脫這種方法。你在用什麼方法?當嘗試使用您的API並在事件失敗時向用戶報告適當的錯誤,而不是嘗試猜測對API的請求是否會事先獲得成功幾乎肯定是一個更好的主意。

+0

我在這裏沒有使用網絡可達性,我正在向已註冊的URL列表發出測試請求,以查看它們是否響應良好。它目前在主線程中,但我知道阻塞性質。我可能會重新考慮這種方法,但重點是在嘗試將排隊對象發送到API之前確保API可用。PS - 我切換到使用'NSOperationQueue'的'waitUntilAllOperationsAreFinished'方法,它似乎工作。感謝您的建議。 – Brenden

+0

@Brenden我假設您的評論「檢查網絡可達性」意味着您使用的是可達性。正如我所說的,你應該*不*嘗試在上傳內容之前使用這種方法檢查API是否「可用」!只要嘗試上傳;如果失敗了,你需要以某種方式處理。即使此方法返回YES,您仍然需要處理實際上傳中的故障,那麼爲什麼還要先檢查? –

+0

@Jesse_Rusak該行由可達性API支持,但我只用它來知道是否存在網絡連接。我通過在此方法中發出請求來驗證連接。你看到這個邏輯有什麼問題嗎? – Brenden