Я пытаюсь загрузить UIImages в фоновый поток, а затем отображать их на iPad. Тем не менее, там заикается, когда я устанавливаю свойство viewViews для изображения. Вскоре я понял, что загрузка изображений ленива на iOS и нашел частичное решение в этом вопросе:
CGImage/UIImage ленивая загрузка на поток пользовательского интерфейса вызывает заикание
Это фактически заставляет изображение загружаться в поток, но при показе изображения все еще заикается.
Здесь вы можете найти мой пример проекта: http://www.jasamer.com/files/SwapTest.zip (изменить: исправлена версия), проверьте SwapTestViewController. Попробуйте перетащить изображение, чтобы увидеть заикание.
Тестовый код, который я создал, это заикание - это (метод forceLoad - это тот, который был сделан из вопроса, который я опубликовал выше):
NSArray* imagePaths = [NSArray arrayWithObjects:
[[NSBundle mainBundle] pathForResource: @"a.png" ofType: nil],
[[NSBundle mainBundle] pathForResource: @"b.png" ofType: nil], nil];
NSOperationQueue* queue = [[NSOperationQueue alloc] init];
[queue addOperationWithBlock: ^(void) {
int imageIndex = 0;
while (true) {
UIImage* image = [[UIImage alloc] initWithContentsOfFile: [imagePaths objectAtIndex: imageIndex]];
imageIndex = (imageIndex+1)%2;
[image forceLoad];
//What missing here?
[self performSelectorOnMainThread: @selector(setImage:) withObject: image waitUntilDone: YES];
[image release];
}
}];
Есть две причины, почему я знаю, что заикания можно избежать:
(1) Apple может загружать изображения без заикания в приложении "Фотографии"
(2) Этот код не вызывает заикания после placeholder1, а placeholder2 отображается один раз в этой модифицированной версии вышеуказанного кода:
UIImage* placeholder1 = [[UIImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource: @"a.png" ofType: nil]];
[placeholder1 forceLoad];
UIImage* placeholder2 = [[UIImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource: @"b.png" ofType: nil]];
[placeholder2 forceLoad];
NSArray* imagePaths = [NSArray arrayWithObjects:
[[NSBundle mainBundle] pathForResource: @"a.png" ofType: nil],
[[NSBundle mainBundle] pathForResource: @"b.png" ofType: nil], nil];
NSOperationQueue* queue = [[NSOperationQueue alloc] init];
[queue addOperationWithBlock: ^(void) {
int imageIndex = 0;
while (true) {
//The image is not actually used here - just to prove that the background thread isn't causing the stutter
UIImage* image = [[UIImage alloc] initWithContentsOfFile: [imagePaths objectAtIndex: imageIndex]];
imageIndex = (imageIndex+1)%2;
[image forceLoad];
if (self.imageView.image==placeholder1) {
[self performSelectorOnMainThread: @selector(setImage:) withObject: placeholder2 waitUntilDone: YES];
} else {
[self performSelectorOnMainThread: @selector(setImage:) withObject: placeholder1 waitUntilDone: YES];
}
[image release];
}
}];
Однако я не могу сохранить все мои изображения в памяти.
Это означает, что forceLoad не выполняет полную работу - там что-то еще происходит, прежде чем изображения будут фактически отображаться. Кто-нибудь знает, что это такое, и как я могу поместить это в фоновый поток?
Спасибо, Джулиан
Обновление
Использовал несколько советов Tommys. Я понял, что это CGSConvertBGRA8888toRGBA8888, что занимает так много времени, поэтому кажется, что это преобразование цвета, которое вызывает отставание. Здесь (перевернутый) стек вызовов этого метода.
Running Symbol Name
6609.0ms CGSConvertBGRA8888toRGBA8888
6609.0ms ripl_Mark
6609.0ms ripl_BltImage
6609.0ms RIPLayerBltImage
6609.0ms ripc_RenderImage
6609.0ms ripc_DrawImage
6609.0ms CGContextDelegateDrawImage
6609.0ms CGContextDrawImage
6609.0ms CA::Render::create_image_by_rendering(CGImage*, CGColorSpace*, bool)
6609.0ms CA::Render::create_image(CGImage*, CGColorSpace*, bool)
6609.0ms CA::Render::copy_image(CGImage*, CGColorSpace*, bool)
6609.0ms CA::Render::prepare_image(CGImage*, CGColorSpace*, bool)
6609.0ms CALayerPrepareCommit_(CALayer*, CA::Transaction*)
6609.0ms CALayerPrepareCommit_(CALayer*, CA::Transaction*)
6609.0ms CALayerPrepareCommit_(CALayer*, CA::Transaction*)
6609.0ms CALayerPrepareCommit_(CALayer*, CA::Transaction*)
6609.0ms CALayerPrepareCommit
6609.0ms CA::Context::commit_transaction(CA::Transaction*)
6609.0ms CA::Transaction::commit()
6609.0ms CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*)
6609.0ms __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__
6609.0ms __CFRunLoopDoObservers
6609.0ms __CFRunLoopRun
6609.0ms CFRunLoopRunSpecific
6609.0ms CFRunLoopRunInMode
6609.0ms GSEventRunModal
6609.0ms GSEventRun
6609.0ms -[UIApplication _run]
6609.0ms UIApplicationMain
6609.0ms main
Последние изменения в бит-маске, которые он предложил, ничего не изменили, к сожалению.