2010-06-28 20 views
8

Jusqu'à iOS 3.2, j'ai utilisé ce genre de code pour charger UIImageView l'image en arrière-plan, et il a bien fonctionné ...iOS4 & fond [UIImage setImage:]

code:

- (void)decodeImageName:(NSString *)name 
{ 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 
    UIImage *newImage = [UIImage imageNamed:name]; 
    [myImageView setImage:newImage]; 
    [pool release]; 
} 
... 
[self performSelectorInBackground:@selector(decodeImageName:) withObject:@"ID"] 

. .. même si [UIImageView setImage:] n'était pas thread-safe!

Mais depuis iOS 4, ça ne marche plus ... Les images apparaissent à l'écran deux secondes après l'appel setImage. Et si je fais un [myImageView performSelectorOnMainThread:@selector(setImage:) withObject:newImage waitUntilDone:YES] au lieu de [myImageView setImage:newImage], les images apparaissent immédiatement mais semblent être re-décodées à la volée (en ignorant le précédent [UIImage imageNamed:] qui aurait dû déjà décoder les données d'image), causant une pause sur mon fil principal. Même si la documentation indique Le cache d'image sous-jacent est partagé entre tous les threads..

Une idée?

+0

Bonjour, merci de poser cette question.Je me demandais pourquoi cela ne fonctionne pas maintenant avec mon application. – GeneCode

Répondre

3

performSelectorInBackground: exécute un sélecteur dans un thread d'arrière-plan. Pourtant, setImage: est une fonction d'interface utilisateur. Les fonctions de l'interface utilisateur ne doivent être exécutées que sur le thread principal. Je n'ai pas d'idée sur le problème particulier, mais c'est le premier réflexe sur ce code, et il se peut que iOS4 gère le mécanisme (non supporté) de l'exécution des fonctions UI dans les threads d'arrière-plan d'une manière différente.

4

Ne le faites pas en arrière-plan! Ce n'est pas sûr pour les threads. Depuis un UIImageView est aussi un NSObject, je pense que l'utilisation -[performSelectorOnMainThread:withObject:waitUntilDone:] sur elle pourrait fonctionner, comme:

[myImageView performSelectorOnMainThread:@selector(setImage:) withObject:newImage waitUntilDone:NO]; 

Et c'est UIImage qui est nouvellement fait thread-safe. UIImageView n'est toujours pas thread-safe.

+1

Salut Evadne, où avez-vous lu que UIImage est thread-safe? Je ne peux pas trouver ça nulle part. – jasongregori

1

Si vous utilisez iOS 4.0, vous devriez vraiment considérer les blocs et les GCD comme vraiment. En utilisant ces technologies, vous pouvez simplement remplacer votre méthode avec:

- (void)decodeImageName:(NSString *)name 
{ 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 
    UIImage *newImage = [UIImage imageNamed:name]; 

    dispatch_async(dispatch_get_main_queue(), ^{ 
     [myImageView setImage:newImage]; 
    } 

    [pool release]; 
} 
+0

Cela n'aide pas beaucoup. Le dispatch_async suspend toujours le thread principal plus longtemps que ce qu'il devrait être comme si le uiimage était re-décodé. Comment puis-je être sûr que le UIImage est décodé après [UIImage imageNamed: name]? –

+0

Je recommanderais de supporter OS 3.1.3 pendant au moins plusieurs mois, et 3.2 jusqu'à quelques mois après la sortie de 4.0+ pour iPad. –

1

Let citation:

@property(nonatomic, readonly) CGImageRef CGImage

Discussion

Si les données d'image a été purgé à cause de la mémoire contraintes, l'appel de cette méthode force le chargement des données en mémoire. Le rechargement des données d'image peut entraîner une pénalité de performance.

Alors vous pourriez être en mesure d'appeler simplement image.CGImage. Je ne pense pas CGImages sont paresseux.

Si cela ne fonctionne pas, vous pouvez forcer un rendu avec quelque chose comme

// Possibly only safe in the main thread... 
UIGraphicsBeginImageContext((CGSize){1,1}); 
[image drawInRect:(CGRect){1,1}]; 
UIGraphicsEndImageContext(); 

Certaines personnes mettent en garde contre la sécurité des threads. Les docs disent UIGraphics{Push,Pop,GetCurrent}Context() sont thread principal seulement, mais ne mentionnent rien sur UIGraphicsBeginImageContext(). Si vous êtes inquiet, utilisez CGBitmapContextCreate et CGContextDrawImage.