Estoy tratando de mejorar el rendimiento de mi aplicación para iPhone con imágenes intensas mediante el uso de una memoria caché de imágenes basada en disco en lugar de pasar por la red. He modelado mi caché de imágenes después de SDImageCache (http://github.com/rs/SDWebImage/blob/master/SDImageCache.m), y es prácticamente lo mismo, pero sin operaciones de entrada/salida de caché asíncronas.Vista de desplazamiento y rendimiento de la vista de tabla al cargar imágenes desde el disco
Tengo algunas vistas de desplazamiento y vistas de tabla que cargan estas imágenes de forma asíncrona. Si la imagen está en el disco, se carga desde la memoria caché de imágenes; de lo contrario, se realiza una solicitud de red y el resultado posterior se almacena en la caché.
El problema al que me estoy enfrentando es que a medida que me desplazo por las vistas de desplazamiento o las vistas de tabla, hay un retraso notable a medida que la imagen se carga desde el disco. En particular, la animación de pasar de una página a otra en una vista de desplazamiento tiene una pequeña congelación en el medio de la transición.
he tratado de solucionar este problema:
- Usando un NSOperationQueue y NSInvocationOperation objetos para hacer las solicitudes de acceso a disco (de la misma manera que SDImageCache), pero no resuelve el problema con el retraso en el todas.
- Afinando el código del controlador de vista de desplazamiento para que solo cargue imágenes cuando la vista de desplazamiento ya no se desplaza. Esto significa que el acceso al disco solo se dispara cuando la vista de desplazamiento deja de desplazarse, pero si inmediatamente trato de desplazarme a la siguiente página, noto el desfase a medida que la imagen se carga desde el disco.
¿Hay alguna manera de que los accesos a mi disco rindan mejor o tengan un efecto menor en la IU?
Tenga en cuenta que ya estoy almacenando en caché las imágenes en la memoria también. Entonces, una vez que todo está cargado en la memoria, la interfaz de usuario es agradable y receptiva. Pero cuando la aplicación se inicia o si se envían advertencias de memoria baja, experimentaré muchos de estos retrasos de UI a medida que las imágenes se cargan desde el disco.
Los fragmentos de código relevantes están a continuación. No creo que esté haciendo nada elegante o loco. El retraso no parece ser notable en un iPhone 3G, pero es bastante evidente en un iPod Touch de 2da generación.
Imagen Código de almacenamiento en caché:
He aquí un fragmento relevante de mi código de la imagen de almacenamiento en caché. Muy claro.
- (BOOL)hasImageDataForURL:(NSString *)url {
return [[NSFileManager defaultManager] fileExistsAtPath:[self cacheFilePathForURL:url]];
}
- (NSData *)imageDataForURL:(NSString *)url {
NSString *filePath = [self cacheFilePathForURL:url];
// Set file last modification date to help enforce LRU caching policy
NSMutableDictionary *attributes = [NSMutableDictionary dictionary];
[attributes setObject:[NSDate date] forKey:NSFileModificationDate];
[[NSFileManager defaultManager] setAttributes:attributes ofItemAtPath:filePath error:NULL];
return [NSData dataWithContentsOfFile:filePath];
}
- (void)storeImageData:(NSData *)data forURL:(NSString *)url {
[[NSFileManager defaultManager] createFileAtPath:[self cacheFilePathForURL:url] contents:data attributes:nil];
}
Scroll código de controlador de vista
He aquí un fragmento correspondiente del código que utilizo para la visualización de imágenes en mis controladores de vista de desplazamiento.
- (void)scrollViewDidScroll:(UIScrollView *)theScrollView {
CGFloat pageWidth = theScrollView.frame.size.width;
NSUInteger index = floor((theScrollView.contentOffset.x - pageWidth/2)/pageWidth) + 1;
[self loadImageFor:[NSNumber numberWithInt:index]];
[self loadImageFor:[NSNumber numberWithInt:index + 1]];
[self loadImageFor:[NSNumber numberWithInt:index - 1]];
}
- (void)loadImageFor:(NSNumber *)index {
if ([index intValue] < 0 || [index intValue] >= [self.photoData count]) {
return;
}
// ... initialize an image loader object that accesses the disk image cache or makes a network request
UIView *iew = [self.views objectForKey:index];
UIImageView *imageView = (UIImageView *) [view viewWithTag:kImageViewTag];
if (imageView.image == nil) {
NSDictionary *photo = [self.photoData objectAtIndex:[index intValue]];
[loader loadImage:[photo objectForKey:@"url"]];
}
}
El objeto cargador imagen es sólo un objeto ligero que comprueba la caché de disco y decide si o no para ir a buscar una imagen de disco o red.Una vez hecho esto, se llama a un método en el controlador de vista de desplazamiento para mostrar la imagen:
- (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;
}
ACTUALIZACIÓN
Estaba experimentando con la aplicación, y he deshabilitado la caché de imágenes y volvió siempre a hacer solicitudes de red. Parece que el simple uso de solicitudes de red para buscar imágenes es , lo que también provoca el mismo retraso al desplazarse por las vistas de desplazamiento y las vistas de tabla. Es decir, cuando una solicitud de red finaliza y la imagen se muestra en la página de vista de desplazamiento o en la celda de la tabla, la IU se retrasa ligeramente un poco y tiene unos pocos segundos de retraso cuando trato de arrastrarlo.
El retraso parece ser más notable cuando se utiliza la memoria caché de disco, ya que el retraso siempre ocurre justo en la transición de la página. ¿Quizás estoy haciendo algo mal al asignar la imagen cargada al UIImageView apropiado?
Además, he intentado usar imágenes pequeñas (miniaturas de 50x50) y el desfase parece mejorar. Por lo tanto, parece que el rendimiento alcanzado se debe a la carga de una imagen grande desde el disco o la carga de una imagen grande en un objeto UIImage. Creo que una mejora sería reducir el tamaño de las imágenes que se cargan en la vista de desplazamiento y las vistas de tabla, que era lo que estaba planeando hacer de todos modos. Sin embargo, simplemente no entiendo cómo otras aplicaciones intensivas de fotos pueden presentar lo que parecen ser fotos de alta resolución en vistas desplazables sin problemas de rendimiento al ir al disco oa través de la red.
Tenemos el mismo problema en iPad con imágenes grandes. Le avisaré si encontramos alguna solución –
Una de las claves principales para el desplazamiento continuo es nunca bloquear el hilo principal. El hilo principal es el hilo de UI, que tiene que gestionar las altas actualizaciones de framerate a la pantalla y las devoluciones de llamada de eventos asociadas a su controlador. Sin ver su código NSUURLConnection, no puedo decir si lo está haciendo en un hilo separado o no, sin embargo, esta sería mi primera corazonada. ¿Puedes publicar tu código de manejo de red? – Yetanotherjosh
compruebe el proyecto TCImageView github. Tienen una implementación bastante ordenada para la carga lenta de imágenes y el almacenamiento en caché del disco https://github.com/totocaster/TCImageView/blob/master/TCImageView.m –