2010-02-13 24 views
10

Estoy creando una aplicación para iPhone que extraerá datos de una API web, incluidas las direcciones de correo electrónico. Me gustaría mostrar una imagen asociada a cada dirección de correo electrónico en las celdas de la tabla, por lo que estoy buscando en la Libreta de direcciones las imágenes y recurriendo a un valor predeterminado si la dirección de correo electrónico no está en el libro. Esto funciona muy bien, pero tengo algunas preocupaciones:¿Cuál es el mejor enfoque para el almacenamiento en caché de imágenes asíncronas en el iPhone?

  • Rendimiento: Las recetas que he encontrado para buscar una dirección de registro de libro de dirección de correo electrónico (o número de teléfono) se informa rather slow. La razón de esto es que debe iterar sobre cada registro de la libreta de direcciones, y para cada uno que tenga una imagen, itere sobre todas las direcciones de correo electrónico para encontrar una coincidencia. Esto puede consumir mucho tiempo para una libreta de direcciones grande, por supuesto.

  • Celdas de tabla: Así que pensé en reunir todas las direcciones de correo electrónico para las que necesito encontrar imágenes y encontrarlas todas a la vez. De esta manera, repito el libro una sola vez para todas las direcciones. Pero esto no funciona bien para las celdas de la tabla, donde cada celda corresponde a una sola dirección de correo electrónico. Tendría que reunir todas las imágenes antes de mostrar las celdas (potencialmente lentas) o hacer que cada celda busque cada imagen a medida que se carga (incluso más lenta, ya que necesitaría repetir el libro para encontrar una coincidencia para cada dirección de correo electrónico).

  • asíncrono de búsqueda: Así que pensé en mirar hacia arriba a granel, pero de forma asíncrona, usando NSInvocationOperation. Para cada imagen encontrada en AddressBook, guardaría una miniatura en el arenero de la aplicación. Entonces cada celda podría simplemente hacer referencia a este archivo y mostrar el predeterminado si no existe (porque no está en el libro o aún no se ha encontrado). Si la imagen se encuentra más tarde en la búsqueda asincrónica, la próxima vez que se muestre la imagen aparecerá de repente. Esto podría funcionar bien para la regeneración periódica de imágenes (por ejemplo, cuando las imágenes se han cambiado en la libreta de direcciones). Pero luego, para cualquier instancia determinada de mi aplicación, una imagen puede no aparecer por un tiempo.

  • asíncrono Tabla celular de búsqueda: Idealmente, me gustaría usar algo así como markjnet's asynchronous table cell updating para actualizar celdas de la tabla con una imagen una vez que se ha descargado. Pero para que esto funcione, tendría que derivar un trabajo NSInvocationOperation para cada celda tal como se muestra y si el icono en la memoria caché no está en la caja de arena. Pero luego volvemos a iterar ineficazmente a través de la libreta de direcciones completa para cada uno, y eso puede ser muchos de ellos si acaba de descargar un montón de nuevas direcciones de correo electrónico.

Así que mi pregunta es: ¿Cómo hacen otros esto? Estuve jugando con Tweetie2, y parece que actualiza las celdas de la tabla de forma asincrónica. Supongo que envía una solicitud HTTP por separado para cada imagen que necesita. Si es así, me imagino que buscar en la libreta de direcciones local por correo electrónico no es menos eficiente, ¿quizás ese sea el mejor enfoque? ¿Simplemente no te preocupes por los problemas de rendimiento asociados con la búsqueda en la libreta de direcciones?

Si es así, ¿está guardando una imagen en miniatura en la caja de arena el mejor enfoque para el almacenamiento en caché? Y si quisiera crear un nuevo trabajo para actualizar todas las miniaturas con cualquier cambio en la libreta de direcciones, diga una vez al día, ¿cuál es el mejor enfoque para hacerlo?

¿Cómo resuelven el resto de ustedes este tipo de problema? ¡Las sugerencias serían muy apreciadas!

Respuesta

2

Independientemente de cuál es la estrategia que utiliza para el almacenamiento en caché real de imágenes, sólo haría una sola pasada a través de los datos de la libreta de direcciones cada vez que reciba una lote de direcciones de correo electrónico, si es posible. (Y sí, lo haría de forma asincrónica.)

Cree un NSMutableDictionary que servirá como memoria caché en la memoria para los resultados de búsqueda. Inicialice este diccionario con cada dirección de correo electrónico de la descarga como una clave, con un centinela como el valor de esa clave (como [NSNull null]).

A continuación, recorra cada ABRecordRef en la libreta de direcciones, llamando al ABRecordCopyValue(record, kABPersonEmailProperty) y recorriendo los resultados en cada ABMultiValue que se devuelve. Si alguna de las direcciones de correo electrónico son claves en su caché, configure [NSNumber numberWithInt:ABRecordGetRecordId(record)] como el valor de esa clave en su diccionario.

Utilizando este diccionario como índice de búsqueda, puede obtener rápidamente las imágenes de ABRecordRefs solo para las direcciones de correo electrónico que está mostrando actualmente en su vista de tabla dada la posición de desplazamiento actual del usuario, como se sugiere en la respuesta de hoopjones. Puede agregar un detector de cambios de la libreta de direcciones para invalidar su caché, activar otra operación de indexación y luego actualizar la vista, si su aplicación necesita ese nivel de "actualización".

+0

Gracias. Así que tarifa En realidad, he implementado una solución que busca una dirección a la vez, pero crea una miniatura y la guarda en el directorio de Documentos de la zona de pruebas. Y sí, solo busca las imágenes en la libreta de direcciones la primera vez que necesitan mostrarse.Creo que * cargar la imagen almacenada en caché desde la caja de arena debe ser lo suficientemente rápida como para que no tenga que ser asincrónica. No necesito el nivel de actualización que describe, así que, a continuación, voy a ver cómo programar actualizaciones periódicas de las miniaturas en caché, y sí, voy a iterar solo a través de la libreta de direcciones. una vez para todos ellos. – theory

+0

Simplemente curioso, ¿cómo puede buscar una dirección a la vez, pero solo iterar una vez a través de la libreta de direcciones? – erikprice

2

Usaría el último método que enumeró (Búsqueda Asincrónica de Células de Tabla) pero solo miro imágenes para los registros actuales que se muestran.Sobrecargo los métodos UIScrollViewDelegate para averiguar cuándo un usuario ha dejado de desplazarse y luego solo empiezo a realizar solicitudes para las celdas visibles actuales.

Algo como esto (esto se modificó ligeramente de un tutorial que encontré en la web, y que no puedo encontrar ahora, se disculpa por no citar el autor):

- (void)loadContentForVisibleCells 
{ 
    NSArray *cells = [self.table visibleCells]; 
    [cells retain]; 
    for (int i = 0; i < [cells count]; i++) 
    { 
     // Go through each cell in the array and call its loadContent method if it responds to it. 
     AddressRecordTableCell *addressTableCell = (AddressRecordTableCell *)[[cells objectAtIndex: i] retain]; 
     [addressTableCell loadImage]; 
     [addressTableCell release]; 
     addressTableCell = nil; 
    } 
    [cells release]; 
} 


- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView; 
{ 
    // Method is called when the decelerating comes to a stop. 
    // Pass visible cells to the cell loading function. If possible change 
    // scrollView to a pointer to your table cell to avoid compiler warnings 
    [self loadContentForVisibleCells]; 
} 


- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate; 
{ 
    if (!decelerate) 
    { 
     [self loadContentForVisibleCells]; 
    } 
} 

Una vez que saben lo que los registros de dirección son actualmente visible, solo haciendo una búsqueda para esos (5 -7 registros probablemente) será muy rápido. Una vez que tomas la imagen, simplemente cántala en un diccionario para que no tengas que volver a hacer la solicitud de la imagen más tarde.

+0

Sólo por curiosidad, ¿por qué este código de ejemplo de retener el NSArray células y luego cada AddressRecordTableCell antes de trabajar con ellos y luego soltarlos, en 'loadContentForVisibleCells'? No veo qué podría causar que se destrakeen durante la ejecución de ese método. – erikprice

+2

Estás en lo correcto. No necesita ser retenido. Escribí este código cuando recién estaba aprendiendo Cocoa, así que hay algo de novato :) – hoopjones

+0

Es bueno saber sobre ['UIScrollViewDelegate'] (http://developer.apple.com/iphone/library/documentation/ UIKit/Reference/UIScrollViewDelegate_Protocol/Reference/UIScrollViewDelegate.html). Eso es lo que usa también el [ejemplo de LazyTableImages] (http://developer.apple.com/iphone/library/samplecode/LazyTableImages/index.html) vinculado por yonel a continuación. Lo curioso es que Tweetie 2 no parece utilizar este enfoque. Cuando me desplazo rápidamente, puedo ver las imágenes cargadas mientras se desplaza. Siempre me molesta que las aplicaciones de Apple no carguen imágenes mientras se desplazan, y Tweetie 2 parece mostrar que no es necesario. – theory

1

Parece que intenta implementar la carga de imágenes diferidas en UITableView. hay un buen ejemplo de Apple, que estoy haciendo referencia aquí: Lazy load images in UITableView

+0

Muchas gracias por el enlace al ejemplo 'LazyTableImages'. No estaba al tanto y me alegra tenerlo para estudiar. – theory

Cuestiones relacionadas