Pull to refresh

Comments 31

так пустой же цикл, вот оптимизатор его и выпилил в релизе.
Он его не просто выпилил. NSLog до этого цикла выполняется, а после него — никогда. Т.е. он в нем виснет.
Оптимизатор перенес переменную из памяти в регистры. Как результат — изменение значения в памяти другим потоком ничего не дает. Почитайте про специальный модификатор volatile — поймете суть проблемы.
Хорошо. Volatile, так volatile. Спасибо за него, кстати.

Но кто-нибудь может объяснить, почему этого в debug build не происходит, а только в release? Перепроверил все флаги и build settings — все одинаково для обеих конфигураций
Еслибы у debug build были бы теже флаги что и у release build — то он бы был release build ;)

Если дебаг инфо генерируется то часть оптимизаций не будет выполняться. Не говоря о препроцессоре с его #ifdef DEBUG… #ifdef NDEBUG…
Это баг в компиляторе же, ты не понял
100 пудово выоптимизировалло нафиг — на stackoverflow есть тоже про это
ответ по выпиливанию — выше
Цикл while выполняется пока isRendering == NO

Если isRendering изменяется в другом потоке без volatile — то не детерминированное количество раз.

Никакого ограничения на количество итераций while нет и быть не может.

А описание проблемы настолько путанное, что локализовать ее тяжело. Возможно, вы изобрели велосипед вместо очереди сообщений.
Да, никогда не делайте синхронизацию (а это именно она) на bool. Используйте NSLock.
Перечитал еще раз про NSLock. Посыпаю голову пеплом, это даже проще, чем мои циклы
А разве за
while (!isRendering) {
}
ещё не обрывают руки? Есть же мониторы, семафоры, мьютексы…
Здесь идет работа в рамках одного потока. Но, насколько я понимаю, поставщиком задач является другой поток. В целом, все сводится к задаче «производители/потребители», которая на iOS решается с помощью GCD и sequential очереди задач. Ну, или NSOperationQueue для слабых духом.
NSOperationQueue начиная с iOS 4 основана на GCD как раз
Возможно, я не слишком копался в ее кишках. GCD показался мне в разы удобнее и я сразу забыл про эту обертку.
не возможно, а вполне явно написано в документации :)
Я бы сказал «определенно», но не заглядывал в документацию, а привычки верить людям на слово не имею :)
За подсказку с NSLock спасибо, в авральном режиме работаем, вылетела из головы эта фича.
По поводу GCD: изначально все писалось на нем, были красивые конструкции вроде dispatch_group_wait и так далее. Но у GCD проблема с рендерингом вьюшек. Поэтому был создан свой класс, унаследованный от NSThread и там была реализована человеческая очередь на выполнение.

Да, вы меня сейчас забросаете помидорами за использование UIKit вне главного потока, но все же это не критично. Ибо главное не обращаться к одной и той же вьюшке из конкурирующих потоков.
У GCD проблемы нет, это у вас проблемы с рендерингом.

Правильный рендеринг на GCD выглядит так:
1. Создаем ContextRef через CreateBitmapContext
2. Рисуем в него как в любой нормальный контекст
3. Создаем из контекста ImageRef
4. Передаем его в основной поток и
4.1. Ставим его в view.layer.contents
4.2. Преобразуем в UIImage и используем в слое-подложке на базе ImageView

А то, что вы делаете — это непонятно что. И оно может отвалиться в любой момент, причем совершенно недетерминированно.
Вообще предпочитаю не обращаться к главному потоку, чтобы не блокировать UI

Да, у GCD во время создания контекста (рендерил пдф) я тоже ловил невнятные и непонятные ошибки, вроде context is null, и cannot restore null context.
Нельзя работать с объектами, живущими в STA потоках вне их потока. Это же основы, что на винде, что на маке.

То, что у вас при этом что-то работает — чудо, а не заслуга.
Вот именно, что два потока. И этот поток тупо жрёт ресурсы.
Любые инструменты, хоть для слабых, хоть для сильных, но не пустые циклы.
и GCD, чтоб вручную треды не городить
Тоже вариант, главное не занимать процессор пустым циклом.
По симптомам — скорее всего компилятор действительно выбросил этот цикл при оптимизации. Тогда вам совершенно необязательно вставлять в цикл sleep, достаточно будет любого выполняемого кода, чтобы компилятор не счел, что цикл ничего не делает. Это если вам именно припекает поскорей залить продукт в App Store.

А вообще в свободное время нужно бы переделать это добро на GCD или NSOperation. Чтобы быстро въехать, что к чему, можно посмотреть эпловое видео, если английский позволяет (https://developer.apple.com/videos/wwdc/2012/, например см. сессию 712)
Читайте, чуть выше объяснил, почему не использовался GCD или NSOperation.
И цикл не выпиливался, NSLog до него выполняется, а после него — нет.
По заголовку уже догадывался, что компилятор выбросил цикл.
Зашел почитать комментарии — так и вышло.
Правило что-ли в PVS-Studio сделать на такие циклы… Уже сколько раз видел аналогичные вопросы.
А вы dead code разве не репортите? А вообще, ИМХО, замечательный пример необходимости образования — не верю, что про такие вещи в ВУЗ'ах не рассказывают совсем.
Dead code — понятие растяжимое. Если имеется в виду бессмысленный код, то что-то ловим, что-то нет. Многий бессмысленный код это продукт использования разнообразных макросов. Таких, например, как UNREFERENCED_PARAMETER. Если речь идёт о недостижимом коде, то с этой задачей хорошо справляются компиляторы. Пока не видно смысла дублировать эту функциональность.
Sign up to leave a comment.

Articles