J'essaie d'améliorer la performance de mon application iPhone intensive d'image en utilisant un cache d'image basé sur disque au lieu de passer sur le réseau. J'ai modélisé mon cache d'image après Sdimagecache ( http://github.com/ RS / SDWEBIMAGE / BLOB / MASTER / SDIMAGECACHACHE.M ), et est à peu près la même chose mais sans cache asynchrones dans les opérations d'entrée / sortie de cache asynchrones.
J'ai des vues de défilement et des vues de table qui chargent ces images de manière asynchrone. Si l'image est sur le disque, elle est chargée à partir du cache d'image, sinon une demande de réseau est effectuée et que le résultat suivant est stocké dans le cache. P>
Le problème que je suis en cours d'exécution, c'est que je fais défiler À travers les vues de défilement ou les vues de table, il existe un décalage notable car l'image est chargée à partir du disque. En particulier, l'animation d'une page d'une page à une autre sur une vue de défilement a un petit gel au milieu de la transition. P>
J'ai essayé de résoudre ce problème par: p>
Notez que je fais déjà la mise en cache du images dans la mémoire aussi. Donc, une fois que tout est chargé en mémoire, l'interface utilisateur est belle et réactive. Mais lorsque l'application démarre, ou si des avertissements de mémoire faible sont expédiés, je vais faire l'expérience de nombreux retards d'interface utilisateur, car les images sont chargées à partir de disque. P> Les extraits de code correspondants sont ci-dessous. Je ne pense pas que je fais quelque chose de fantaisie ou de fou. Le décalage ne semble pas être perceptible sur un iPhone 3G, mais il est assez apparent sur un iPod Touch 2nd-Gen. P> Cache de cache d'image: strong> P> Voici un extrait pertinent de mon code de cache d'image. Assez simple. P> Vue du défilement Code du contrôleur strong> p> Voici un extrait pertinent du code que j'utilise pour afficher des images dans Mes contrôleurs de vue de défilement. P> - (void)imageLoadedFor:(NSNumber *)index image:(UIImage *)image {
// Cache image in memory
// ...
UIView *view = [self.views objectForKey:index];
UIImageView *imageView = (UIImageView *) [view viewWithTag:kImageViewTag];
imageView.contentMode = UIViewContentModeScaleAspectFill;
imageView.image = image;
}
5 Réponses :
L'image du disque est en réalité lue lors du dessin de l'image sur l'imageView. Même si nous mettons en cache la lecture de l'image du disque, cela n'affecte pas car il ne conserve que la référence au fichier. Vous devrez peut-être utiliser un carrelage d'images plus grandes à cette fin. P>
Cordialement, Deepa p>
Vous devriez consulter l'application de l'exemple LazyTableImages. p>
Si vous avez réduit l'activité de réseau, j'essaierais d'encapsuler votre demande pour vous assurer qu'elle est à 100% du fil principal. Bien que vous puissiez utiliser NsurlConnection de manière asynchrone et répondre à ses méthodes de déléguement, je trouve plus facile d'envelopper une demande synchrone dans une opération d'arrière-plan. Vous pouvez utiliser Nsoperation ou une expédition centrale Grand si vos besoins sont plus complexes. Un exemple (relativement) simple dans une implémentation d'ImageLoader pourrait être:
// imageLoader.m // assumes that that imageCache uses kvp to look for images - (UIImage *)imageForKey:(NSString *)key { // check if we already have the image in memory UImage *image = [_images objectForKey:key]; // if we don't have an image: // 1) start a background task to load an image from a file or URL // 2) return a default image to display while loading if (!image) { [self performSelectorInBackground:@selector(loadImageForKey) withObject:key]; image = [self defaultImage]; } return image; } - (void)loadImageForKey:(NSString *)key { NSAutoReleasePool *pool = [[NSAutoReleasePool alloc] init]; // attempt to load the image from the file cache UIImage *image = [self imageFromFileForKey:key]; // if no image, load the image from the URL if (!image) { image = [self imageFromURLForKey:key]; } // if no image, return default or imageNotFound image if (!image) { image = [self notFoundImage]; } if ([_delegate respondsTo:@selector(imageLoader:didLoadImage:ForKey:)]) { [_delegate imageLoader:self didLoadImage:image forKey:key]; } [pool release]; } - (UIImage *)imageFromURLForKey:(NSString *)key { NSError *error = nil; NSData *imageData = [NSData dataWithContentsOfURL:[self imageURLForKey:key] options:0 error:&error]; UIImage *image; // handle error if necessary if (error) { image = [self errorImage]; } // create image from data else { image = [UIImage imageWithData:imageData]; } return image; }
J'ai eu ce problème - vous frappez la limite de la rapidité avec laquelle l'interface utilisateur peut charger une image lors du défilement - je vais donc contourner le problème et améliorer l'expérience utilisateur. P>
C'est généralement le décodage de l'image qui prend du temps, ce qui provoque une gel des interfaces internes (puisque tout se passe sur le fil principal). Chaque fois que vous appelez Deux options: P>
Je préfère la deuxième approche; C'est assez facile avec GDC de nos jours. P> [UIIMAGE ImageWithData:] code> sur une grande image, vous remarquerez un hoquet. Décodage Une image plus petite est beaucoup plus rapide. P>
Didfinishscrolling code>. Les vignettes doivent décoder rapidement suffisamment de telle sorte que vous ignorez de cadres. Li>
Nous avons le même problème sur iPad avec de grandes images. Je vous ferai savoir si nous trouvons une solution
L'une des touches principales du défilement performant est de ne jamais bloquer le fil principal. Le thread principal est le fil d'interface utilisateur, qui doit gérer les mises à jour élevées de framerate à l'écran et les rappels événementiels associés à votre contrôleur. Sans voir votre code NsuurlConnection, je ne peux pas dire si vous le faites dans un fil séparé ou non, ce serait ce que ce soit mon premier chasseur. Pouvez-vous publier votre code de traitement du réseau?
Vérifiez le projet TCIMageView GitHub. Ils ont une jolie mise en œuvre soignée pour les images de chargement paresseux et la cache-disque github.com/totocaster /TcImageView/blob/master/tcimageview.m
Checkout Uiimageloader - Github.com/gngrwzrd/uiimageloader