2014-10-12 5 views
1

В моем приложении я обрабатываю партии (от 200 до 400) UIImage s на фоновом потоке, а затем устанавливаю их внутри на экране UIImageView экземпляров, отправив блок обновления пользовательского интерфейса в основной поток.Безопасность на экране UIView

Некоторый код, чтобы показать примерно то, что я делаю ...

dispatch_async(redrawQueue, ^{ 
    // An array to stuff images in to for the views that have one. 
    NSMutableArray *const images = [NSMutableArray arrayWithCount: [activeViews count] value: [NSNull null]]; 

    for(NSUInteger i=0; i<activeCount; ++i) 
    { 
    // Rendered content comes from a block in myState. 
    UIImage *const image = contentBlock(i); 
    if(image) 
    { 
     images[i] = image; 
    } 
    } 
    else 
    { 
    return; 
    } 

    // Update the UI now… 
    dispatch_async(dispatch_get_main_queue(), ^{ 
    [images enumerateObjectsUsingBlock:^(UIImage *image, NSUInteger i, BOOL *stop) { 
     UIImageView *const view = [activeViews objectAtIndex:i]; 
     [view setImage: [NSNull isNotNull: image] ? image : nil]; 
     layoutBlock(view, i); 
    }]; 
    }); 
}); 

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

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

Может кто-нибудь предложить, если это вряд ли будет потокобезопасным?

Я сделал небольшой тест на выделение экранов UIViews на фоновый поток и вложен их друг в друга. Он еще не разбился :-) «Он еще не разбился», однако, это не отличная гарантия безопасности потока! Он также ничего не говорит о том, что может произойти в будущей версии iOS.


Очевидный ответ на это «Эй, ты, дурак, почему вы используете сотни маленьких взглядов? Композит их к одному большому изображению и иметь один вид вы поменять его на сайте.» К сожалению, мне нужно много маленьких просмотров, потому что мне нужно перемещать отдельные маленькие кусочки независимо.

Другой ответ может быть «Используйте спрайтов комплект, чувак», и вы, вероятно, правы, но маленькие точки зрения имеют динамический размер и содержание, и я не знаю, как оптимальный набор спрайтов, когда есть много появляются спрайты.

Третий подход может заключаться в том, чтобы дросселировать обновления пользовательского интерфейса в основном потоке, чтобы предотвратить падение кадров. Есть ли механизм, который это делает? Какая-то очередь отправки запускается основным потоком, который вызывает только мелочи, пока у него осталось много времени?

+0

Для чего это стоит, я пробовал это. Это не сбой, но он не работает. Когда я добавляю предварительно заполненный вид контейнера (в основном потоке), содержимое не появляется. Он ошибочно начинает появляться через некоторое время, но не в какой-либо полезной или надежной форме. Вероятно, это не стартер. – Benjohn

ответ

2

Вы спросили:

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

Это не то, что встроено, но не так уж сложно представить, как вы можете это сделать, но это также нетривиально. Вам, вероятно, понадобится управлять собственным массивом изображений для доставки (включая некоторые средства защиты от параллельного доступа), а затем добавить CFRunLoopObserver (возможно, в действии kCFRunLoopBeforeWaiting, так как тогда цикл запуска собирается заснуть), что , каждый раз, когда он запускается, отмечает время начала, а затем обрабатывает элементы из вашего массива изображений до тех пор, пока не пройдет некоторое количество времени (10 мс, вероятно, приличное количество времени).

Еще одна вещь, которую вы могли бы подумать, - это преобразовать многие из этих маленьких изображений в один CGImage (или небольшое количество изображений), а затем установить содержимое слоя представления на большое изображение, а также установить границы, чтобы каждый экземпляр обрезается до той части, которая соответствует этой точке зрения. Это может уменьшить количество загрузок текстур графического процессора (и, следовательно, общие накладные расходы), так как все CALayers, поддерживающие представления, будут иметь то же изображение, что и их содержимое. Вероятно, это будет моя первая остановка.

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