NSRunLoop иногда делает приложение не отвечающим

В моем приложении мне нужно сделать https-вызовы для спокойного веб-API и обработать результаты по возвращении. Количество одновременных вызовов службы никогда не фиксируется, поэтому соответствующий код был написан соответствующим образом. Данные, полученные из службы, временно хранятся в базе данных SQLite в приложении. Ниже приведена структура, как это работает.

Когда пользователь переходит к любому экрану или его компоненту пользовательского интерфейса, для которого необходимо извлечь данные, контроллер представления вызывает метод для своего назначенного объекта модели. Затем этот метод проверяет, присутствуют ли данные уже в БД или их необходимо извлечь. Если данные присутствуют, они возвращаются контроллеру представления. В противном случае он инициирует асинхронный сервисный запрос и ждет, пока придет ответ, после чего возвращает данные в ВК. Таким образом, VC инициализирует индикатор загрузки перед вызовом указанной модели и закрывает его после возврата управления из этой функции.

Здесь важно, чтобы функция модели ждала ответа от веб-API. Это делается путем регистрации NSNotification, которое будет выдано служебным модулем после того, как возвращенные данные будут записаны в БД. Логическая переменная, для которой устанавливается значение false при выполнении запроса на обслуживание и значение true после получения ответа. NSRunLoop запускается при ложном условии этой логической переменной. Следовательно, когда для переменной установлено значение true, остальная часть обработки может продолжаться.

Ниже приведены соответствующие фрагменты кода, в которых все это реализовано:

[serviceModule initServiceCall:@"25" withDictionary:[NSDictionary dictionaryWithObjects:@[asOfDate] forKeys:@[@"toDate"]]];

    dataReady=NO;

    NSString *notificationName = @"dataReady";
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(useNotificationFromServiceModule:) name:notificationName object:nil];

    NSRunLoop *theRL = [NSRunLoop currentRunLoop];
    while (!dataReady && [theRL runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]);

Остальная часть функции продолжается после этого.

Это функция, которая обрабатывает уведомление:

-(void)useNotificationFromServiceModule:(NSNotification *)notification {
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0ul);
dispatch_async(queue, ^{
    dataReady=YES;
});}

Обычный процесс заключается в том, что после отправки уведомления NSRunLoop завершает работу, и остальная часть метода завершается, возвращаясь к контроллеру представления, который затем отклоняет индикатор загрузки. Проблема в том, что иногда этого не происходит. Пока выдается уведомление (вижу лог консоли), NSRunLoop не заканчивается. Индикатор загрузки продолжает появляться на экране и остается таким до тех пор, пока экран не будет нажат один раз. При касании экрана NSRunLoop завершается, а остальная часть процесса продолжается случайным образом.

Это происходит не всегда. Это происходит совершенно случайно, может быть, примерно 4-5 раз из 10. Пожалуйста, предоставьте некоторые входные данные/указатели, чтобы указать, почему это может происходить.


person Swarnava Maitra    schedule 09.06.2014    source источник
comment
почему вы используете runloop в своем коде?   -  person Bryan Chen    schedule 09.06.2014
comment
установка для dataReady значения yes не приведет к возврату этого метода [theRL runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]].   -  person KudoCC    schedule 09.06.2014


Ответы (1)


Если вы используете цикл выполнения напрямую, вы либо очень умны, либо очень глупы. В первом случае вы найдете ответ сами. Во втором случае было бы намного лучше, если бы вы следовали тому же шаблону, что и все остальные, то есть запуск вашего сетевого кода в фоновом потоке и использование dispatch_async при получении результатов.

person gnasher729    schedule 09.06.2014