2013-12-21 5 views
1

Мое предположение состоит в том, что operation s работают асинхронно в отдельном потоке, но цикл никогда не выходит, поэтому что-то не так, как я предполагал.Почему этот цикл не закончился

/** 
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

Я считаю, что проблема в том, что я не использовал замок, чтобы увеличить счетчики поэтому цикл в то время как никогда не будет вычисляться 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

Несколько предложений:

  • Никогда не проверять достижимость, чтобы определить, является ли запрос будет успешным. Вы должны попробовать запрос; только если он терпит неудачу, если вы проконсультируетесь о достижении цели, чтобы попытаться получить наилучшее представление о том, почему. Достижимость делает no гарантией того, что запрос не удастся или удастся.

  • Этот метод называется главной темой? Даже если вы исправили проблему с запросами, которые никогда не завершатся, она будет блокировать пользовательский интерфейс все время, когда будут запущены ваши сетевые запросы. Поскольку эти запросы могут длиться довольно долго, это плохой опыт для пользователя, а также то, что ОС убьет ваше приложение, если это произойдет не в то время (например, при запуске).

  • Зацикливание при вызове сна или его эквивалента является расточительным для ресурсов ЦП и памяти, а также предотвращает обслуживание runloop потока от обслуживания любых таймеров, обработчиков событий или обратных вызовов. (Вероятно, поэтому блокировки сетевого взаимодействия никогда не запускаются.) Если вы можете избежать блокировки потока, вы должны. Кроме того, Cocoa очень часто будет недовольна, если вы сделаете это на NSThread, который вы сами не создали.

Я вижу два варианта:

  1. Использование dispatch_group сек ждать всех ваших запросов, чтобы закончить. Вместо того, чтобы блокировать ваш вызывающий поток, вместо этого вы должны сделать блок завершения, чтобы позвонить, когда закончите. Итак, вместо возврата BOOL возьмите блок завершения, который принимает BOOL. Что-то вроде - (void)determineIfAPIIsAvailable:(void(^)(BOOL))completionBlock;

  2. Избавьтесь от этого метода в целом. Для чего вы используете этот метод? Это почти наверняка лучшая идея просто попытаться использовать ваш API и сообщать о соответствующих ошибках пользователю, когда что-то не работает, а не пытаться угадать, будет ли запрос к API успешным.

+0

Я не использую доступность сети здесь, я делаю тестовые запросы в список зарегистрированных URL-адресов, чтобы проверить, хорошо ли они отвечают. В настоящее время он находится в основном потоке, но я знаю о блокирующем характере. Я могу переосмыслить этот метод, но главное - убедиться, что API-интерфейсы доступны, прежде чем пытаться отправить объекты в очередь в API.PS - я переключился на использование 'NSOperationQueue'' waitUntilAllOperationsAreFinished', и, похоже, он работает. Спасибо за ваши предложения. – Brenden

+0

@Brenden Я предполагал, что ваш комментарий «Проверить доступность сети» означает, что вы используете доступность. Как я уже сказал, вы должны * не пытаться проверить, доступен ли API, используя такой метод, прежде чем вы что-то загрузите! Просто попробуйте загрузить; если он терпит неудачу, вам нужно как-то это обработать. Даже если этот метод возвращает ДА, вам все равно нужно обрабатывать сбои в фактических загрузках, так зачем сначала проверять проверку? –

+0

@Jesse_Rusak эта линия поддерживается API доступности, но я использую его только для того, чтобы узнать, присутствует ли сетевое соединение. Я проверяю соединение, делая запросы в этом методе. Вы видите что-то не так с этой логикой? – Brenden

Смежные вопросы