Pull to refresh

Странности с циклами: в debug работает, в release нет

Reading time2 min
Views2.9K
День добрый, хабраюзеры.

Давно я ничего не писал, но здесь просто вопиющий случай. Я с недавних пор пишу на Objective C, сталкивался со многими и многими непонятными ситуациями, из которых мог искать выход день и два. В итоге все решалось и оказывалось банальным и простым. К тому же «все это уже было в Симпсонах» — после локализации проблемы ее решение находилось на первой странице гугла.

Но здесь! Отладил приложение, собрал в архив для AppStore, решил перепроверить на устройстве — полезли баги.

Что бывает и как с этим бороться — предлагаю обсудить ниже


Итак, программа моя выполняла следующее:
В главном потоке (буду для простоты здесь и далее называть Threads потоками) отображается глобальный UIScrollView, в котором рендерятся изображения, текст, аудио и видео. Для текущей открытой страницы рендеринг осуществляется в этом же главном потоке. Для плавности перехода на соседние страницы, в отдельно созданных потоках выполняется предварительный рендеринг (фото низкого разрешения растягивается на экран), и полный рендеринг. Назовем поток с предварительным рендерингом потоком №1, с полным — потоком №2.

Для чего нужен предварительный рендеринг? Чтобы пользователь мог быстро-быстро перелистывать страницы и видеть низкокачественную страницу, а не ждать каждый раз загрузки полной версии.
Полный рендеринг — тут понятно. Человек читает одну страницу, переходит на соседнюю — а там уже всё подгружено, и запускается на очередь «новая» соседняя.

К слову — нельзя же рендерить одну страницу одновременно из двух потоков, поэтому и поток №1, и поток №2, дожидались окончания рендеринга текущей страницы кем бы то ни было, и потом уже проверяли — есть ли предварительный/полный рендеринг или нет, и в зависимости от этого осуществляли задуманное, либо выходили.
Для всего этого использовался флаг BOOL isRendering. И в методах -(void) preRenderPage и -(void) fullRenderPage находилась вот такая конструкция:

while (!isRendering) {
}
isRendering = YES;

… //непосредственно рендеринг

isRendering = NO;
return;

Все замечательно работало при запуске из xcode, но переставало работать при запуске Archive/release build.
На локализацию проблемы у меня ушел весь рабочий день, а вот после — я не нашел ни одного упоминания о ней. Итак, внимание!
Если цикл ожидания изменить вот так:
while(!isRendering) {
[NSThread sleepForTimeInterval:0.01];
}
то все снова работает, как и в девелоперском билде.

У меня есть только версия, что цикл while может запускаться лимитированное количество раз. При запуске из xcode после каждой инструкции программа общается со средой разработки, потому и работает медленнее. При запуске релизного варианта такой задержки нет, цикл while выполняется слишком много раз, и он убивается. Либо подвешивается в suspend и больше не выполняется.

Вот такие дела.

Быть может, я в принципе криво реализовал ожидание разрешающего флага, и стоило это сделать по-другому. Раскройте мне глаза :) Может есть что-то банальнее и проще.

PS вариант с NSRunLoop и [NSDate distantFuture] не рассматривал, т.к. он при отсутствии команд выполняется только один раз. А делать [NSDate dateWithTimeIntervalSinceNow:0.01] — по моему мнению никак не отличается от моего решения, да и более громоздкое.
Tags:
Hubs:
-17
Comments31

Articles