Pregunta UITableView es lento cuando se desplaza hacia arriba


Solución: use SDWebImage: https://github.com/rs/SDWebImage

Tengo un UITableView que se vuelve muy lento cuando se desplaza. Descubrí que el retraso aparece cuando la imagen que estoy usando regresa a la pantalla.

Estoy usando una UITableViewCell personalizada. ¿Es esto también una razón por la cual está rezagado?

Mi UITableViewCell personalizado:

enter image description here

Mi código:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

NSString *CellIdentifier = [NSString stringWithFormat:@"Cell%d%d",indexPath.row,indexPath.section];


tableViewCellActiviteiten *cell = (tableViewCellActiviteiten *)[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];

if (cell == nil)
{

    NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"tableViewCellActiviteiten" owner:self options:nil];
    cell = (tableViewCellActiviteiten *)[nib objectAtIndex:0];
}


cell.thetitle.text = [self.alletitels objectAtIndex:indexPath.row];
cell.thesubtitle.text = [self.allesubtitels objectAtIndex:indexPath.row];

NSString * imagePath = [self.alleimages objectAtIndex:indexPath.row];

NSURL * imageURL = [NSURL URLWithString:imagePath];
NSData * imageData = [NSData dataWithContentsOfURL:imageURL];
UIImage * image = [UIImage imageWithData:imageData];

cell.image.image = image;

return cell;

}

Contenido de las matrices:

self.alletitels contiene una cadena: "Título de actividad"

self.allesubtitels contiene una cadena: "Subtítulo de actividad"

self.alleimages contiene una url: "http://m2.myhappygames.com//files/pics/0/Paranormal_Shark_Activity_3.jpg"

¿Alguien puede aconsejar cuál puede ser la causa del desplazamiento lento?


14
2017-09-18 12:52


origen


Respuestas:


El problema es que cada vez tableView: cellForRowAtIndexPath: método se llama código que genera una imagen. Se llamará cada vez que aparezca una celda en la pantalla, por lo tanto, si se desplaza muy rápido, este método comenzará a asignar muchas imágenes de forma síncrona, lo que ralentizará el desplazamiento.

Como solución rápida, implemente NSCache en su Controlador de Vista y almacene imágenes en él.

UIImage *image = [_imageCache objectForKey:@indexPath.row];
if (image == nil) {
    NSString * imagePath = [self.alleimages objectAtIndex:indexPath.row];
    NSURL * imageURL = [NSURL URLWithString:imagePath];
    NSData * imageData = [NSData dataWithContentsOfURL:imageURL];
    image = [UIImage imageWithData:imageData];
    [_imageCache setObject:image forKey:@indexPath.row];
}

cell.image.image = image;

_imageCahce es una variable de instancia del controlador de vista que puede implementar.

Espero que esto ayude, ¡salud!


9
2017-09-18 13:02



Estas dos líneas aquí:

NSData * imageData = [NSData dataWithContentsOfURL:imageURL];
UIImage * image = [UIImage imageWithData:imageData];

¿Qué está frenando dramáticamente el rendimiento de su mesa?

Está realizando una búsqueda sincrónica y carga de datos de imagen cada vez refrescas esa celda

Sería más inteligente almacenar en caché de algún modo (o guardar localmente) las imágenes que se mostrarán. Y si no se guardan localmente o en un caché, solo entonces ve a buscar esas imágenes (y hazlo de manera asícrona, fuera de eso "cellForRowAtIndexPath:"método).


6
2017-09-18 12:55



Está realizando llamadas de red sincrónicas para descargar las imágenes mientras se crea la célula. Estas llamadas bloquean el hilo principal hasta la imagen de descargas de células. El tiempo de retardo variará en función de la calidad de la red.

La solución para esto es el uso de la técnica llamada "carga lenta". En esta técnica, la carga de la imagen se realizará en una secuencia separada, desbloqueando así el hilo principal. La imagen se descarga y luego se aplica al contenedor correcto UIImageView. Aquí está Código de ejemplo de Apple para la carga diferida de imágenes en la vista de tabla.

También puedes usar SDWebImage. Esto también hará el almacenamiento en caché de imágenes para usted.

#import <SDWebImage/UIImageView+WebCache.h>

...

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *MyIdentifier = @"MyIdentifier";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];

    if (cell == nil)
    {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
                                       reuseIdentifier:MyIdentifier] autorelease];
    }

    // Here we use the new provided setImageWithURL: method to load the web image
    [cell.imageView setImageWithURL:[NSURL URLWithString:@"http://www.domain.com/path/to/image.jpg"]
                   placeholderImage:[UIImage imageNamed:@"placeholder.png"]];

    return cell;
}

¡Espero que ayude!


4
2017-09-18 13:07



Junto con el almacenamiento en caché, también puede considerar cargar las imágenes en segundo plano mediante Grand Central dispatch. Cuando la celda está cargada, coloque un UIActivityIndicator y luego reemplácelo con una imagen en una secuencia separada.

// get a data provider referencing the relevant file
CGDataProviderRef dataProvider = CGDataProviderCreateWithFilename(filename);

// use the data provider to get a CGImage; release the data provider
CGImageRef image = CGImageCreateWithPNGDataProvider(dataProvider, NULL, NO, 
                                                kCGRenderingIntentDefault);
CGDataProviderRelease(dataProvider);

// make a bitmap context of a suitable size to draw to, forcing decode
size_t width = CGImageGetWidth(image);
size_t height = CGImageGetHeight(image);
unsigned char *imageBuffer = (unsigned char *)malloc(width*height*4);

CGColorSpaceRef colourSpace = CGColorSpaceCreateDeviceRGB();

CGContextRef imageContext =
CGBitmapContextCreate(imageBuffer, width, height, 8, width*4, colourSpace,
              kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little);

CGColorSpaceRelease(colourSpace);

// draw the image to the context, release it
CGContextDrawImage(imageContext, CGRectMake(0, 0, width, height), image);
CGImageRelease(image);

// now get an image ref from the context
CGImageRef outputImage = CGBitmapContextCreateImage(imageContext);

// post that off to the main thread, where you might do something like
// [UIImage imageWithCGImage:outputImage]
[self performSelectorOnMainThread:@selector(haveThisImage:) 
     withObject:[NSValue valueWithPointer:outputImage] waitUntilDone:YES];

// clean up
CGImageRelease(outputImage);
CGContextRelease(imageContext);
free(imageBuffer);

También puedes usar UIImage + ImmediateLoad.m   Decodifica imágenes de inmediato. Además de UIImage -initwithContentsOfFile :, -imageWithCGImage: y CG * son seguros para subprocesos después de iOS4.


3
2017-09-24 18:12



Está intentando cargar imágenes en el mismo subproceso de interfaz de usuario donde está desplazándose. Debe cargarlos en la memoria caché en segundo plano y luego obtener de la memoria caché cuando estén listos para mostrarse.


2
2017-09-18 12:57



Tuve un problema similar, lo examiné con Profiler, así que aquí hay algunos consejos:

1) Está utilizando incorrectamente el identificador reutilizable, siempre debe usar el mismo identificador.

en lugar de esto:

NSString *CellIdentifier = [NSString stringWithFormat:@"Cell%d%d",indexPath.row,indexPath.section];

utilizar esta:

NSString *CellIdentifier = @"MyIdentifier";

para más información: cómo usar UItableViewCell reuseIdentifier

2) El método loadNibNamed es realmente lento (además de que lo estás cargando cada vez para cada celda), debes deshacerte del plumín y colocar los elementos de la UI del código sobrescribiendo este método de una UITableViewCell

-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier;

3) uso Instrumentos


2
2017-09-23 13:55



Está realizando una llamada de red síncrona para cada imagen. Es por eso que está quedando rezagado en su aplicación. Tratar AsyncImageView  descargará sus imágenes de la web de forma asíncrona. Y podrás eliminar el retraso de tu aplicación. :-)


2
2017-09-24 14:03