J'essaie de charger des images UII dans un fil d'arrière-plan, puis de les afficher sur l'iPad. Cependant, il y a un bégaiement lorsque je règle la propriété view des imageViews sur l'image. J'ai vite compris que le chargement des images est paresseux sur iOS, et j'ai trouvé une solution partielle dans cette question :
Cela force effectivement l'image à être chargée dans le fil de discussion, mais il y a toujours un bégaiement lors de l'affichage de l'image.
Vous pouvez trouver mon exemple de projet ici : http://www.jasamer.com/files/SwapTest.zip (éditer : version fixe ), vérifiez le SwapTestViewController. Essayez de faire glisser l'image pour voir le bégaiement.
Le code de test que j'ai créé et qui bégaie est le suivant (la méthode forceLoad est celle reprise de la question de stack overflow que j'ai postée ci-dessus) :
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's missing here?
[self performSelectorOnMainThread: @selector(setImage:) withObject: image waitUntilDone: YES];
[image release];
}
}];
Il y a deux raisons pour lesquelles je sais que le bégaiement peut être évité :
(1) Apple est capable de charger les images sans bégaiement dans l'application Photos.
(2) Ce code ne provoque pas de bégaiement après que les placeholder1 et placeholder2 ont été affichés une fois dans cette version modifiée du code ci-dessus :
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];
}
}];
Cependant, je ne peux pas garder toutes mes images en mémoire.
Cela implique que forceLoad ne fait pas tout le travail - il y a quelque chose d'autre qui se passe avant que les images soient effectivement affichées. Quelqu'un sait-il ce que c'est, et comment je peux le mettre dans le fil d'arrière-plan ?
Merci, Julian
Mise à jour
J'ai utilisé quelques-uns des conseils de Tommys. Ce que j'ai découvert, c'est que c'est CGSConvertBGRA8888toRGBA8888 qui prend autant de temps, donc il semble que ce soit une conversion de couleur qui cause le décalage. Voici la pile d'appels (inversée) de cette méthode.
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
Les derniers changements de masque de bits qu'il a proposés n'ont rien changé, malheureusement.