2016-01-13 3 views
0

У меня есть метод в приложении iOS, который должен вернуть значение bool в зависимости от того, удастся ли веб-вызов или нет.iOS Выполнение стоп-кадра от прогрессирования до завершения блока

Веб-вызов структурирован таким образом, что он принимает блок как параметр обратного вызова и этот обратный вызов вызывается, когда веб-вызов имеет результат. Исходя из этого результата, мой метод должен вернуть значение True/False.

Итак, мне нужно остановить выполнение от дальнейшего прогресса, не получив результата.

Я пытаюсь достичь этого через семафоры, посмотрев на некоторые примеры, которые другие поделили, но обратный вызов никогда не вызывается, если я удалю семафор, тогда обратный вызов всегда вызывается.

Что мне здесь не хватает?

+ (BOOL)getUserInformation { 
__block BOOL flag = false; 

dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); 

[[WebServicesManager sharedManager] getUserInformationWithCallback:^(NSInteger statusCode, NSString *response, NSDictionary *responseHeaders, id obj, NSError *error) { 

    if (error) { 
     //Handle error case and perform appropriate cleanup actions. 
    } 
    else 
    { 
     //Save user information 
     flag = true; 
    } 

    dispatch_semaphore_signal(semaphore); 
}]; 

dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); 

return flag; 
} 

я ставлю точку останова на if(error), чтобы проверить, если обратный вызов вызывается, он не делает, если я не удалить семафор.

Я мог бы дать этому методу свой собственный блок обратного вызова, или я мог бы дать содержащему классу делегата и добиться того, что мне нужно, но я бы очень хотел, чтобы этот подход работал.

+2

Просто Hinch: это неопределенные 'WebServicesManager' dispatc hing это обратный вызов к основному потоку, который ждет семафора? – SmokeDispenser

+0

Хммм, это имеет смысл, я проверю. –

+0

Ян прав. Но, для протокола, это очень, очень плохая практика. Вы собираетесь заблокировать поток, которого вы никогда не должны делать (если вам не повезло в вашем сроке, это может привести к тому, что процесс сторожевого копирования приведет к удалению вашего приложения, это ужасный UX и т. Д.). Вы должны реорганизовать свой код, который вызывает это, чтобы принять асинхронные шаблоны. Если вам нужна помощь в этом, отредактируйте свой вопрос и покажите нам, как вы называете 'getUserInformation', и как поток продолжается, и мы можем предложить дальнейшие советы. – Rob

ответ

0

Вы, несомненно, зашли в тупик, потому что используете семафор в том же потоке, с которым менеджер веб-сервисов (или API, который использует) отправляет свой обработчик завершения.

Если вы хотите исполнение, исключающую сценарий тупиковый, но и позволяет избежать ошибок блокирования основной поток, вы можете сделать что-то вроде:

+ (void)getUserInformation:(nonnull void (^)(BOOL))completionHandler { 
    [[WebServicesManager sharedManager] getUserInformationWithCallback:^(NSInteger statusCode, NSString *response, NSDictionary *responseHeaders, id obj, NSError *error) { 
     if (error) { 
      completionHandler(false); 
     } else { 
      //Save user information 
      completionHandler(true); 
     } 
    }]; 
} 

Затем, вместо того, чтобы делать что-то вроде:

BOOL success = [YourClass getUserInformation]; 
if (success) { 
    ... 
} 

Вы можете вместо этого сделать:

[YourClass getUserInformation:^(BOOL success) { 
    if (success) { 
     ... 
    } 
}]; 

// but do not try to use `success` here ... put everything 
// contingent upon success inside the above completion handler 
+0

Rob, я уже использую это решение с другими вызовами в приложении. Это было мое желание найти альтернативное решение, которое привлекло к себе семафоры. На данный момент я обновил свой код для работы с обработчиком завершения. Я наткнулся на другой ответ, от вас, на другой вопрос, где вы продемонстрировали, как два потока обменивались с семафорами, я пытался использовать это, но все равно не мог заставить его работать. Как я могу обновить код, в вопросе, использовать семафоры вместе с разными потоками и не блокировать? –

+0

Да, семафорный подход может легко зайти в тупик, если вы не будете осторожны. Вероятно, вы можете реорганизовать API веб-сервисов, чтобы избежать этой проблемы, но я лично не буду тратить лишнюю секунду на то, чтобы выяснить, как исправить вашу проблему взаимоблокировки, исключительно для написания кода для блокирования основного потока. Я знаю, что сразу возвращающ значение сразу настолько соблазнительно (это кажется настолько логичным), но по множеству причин это ужасная практика с негативными последствиями. Серьезно, не делай этого. – Rob

+0

Рефакторинг класса WebServices не является вариантом, который я бы хотел рассмотреть, он будет иметь далеко идущие последствия и может означать конец слова, как мы его знаем. Позвольте этому идти, пока я «действительно действительно» не буду использовать семафоры где-то :) –

2

WebServicesManager, вероятно, отправляет его в тот же поток, с которым семафор ждет.

Как @Rob правильно упоминает в комментариях, это, скорее всего, не очень хорошая идея сделать на основной теме; скорее используйте асинхронную модель, а не блокируйте основной поток в течение минут, пока соединение не сможет время ожидания при определенных обстоятельствах, замораживая ваш пользовательский интерфейс.

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