2012-02-14 10 views
8

Tengo una vista de tabla con secciones, que se pueden abrir y cerrar. Entonces, cuando toco una sección para abrirla, se está llenando de celdas y se llama a -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *) exactamente tantas veces como las proporcioné en -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section.tableView: cellForRowAtIndexPath: recibe una llamada no solo para las celdas visibles?

¿Es correcto? ¿No debería ser solo el número de celdas visibles?

Porque en mi caso tengo una mala situación: tengo un montón de celdas personalizadas (50 ~ 100 celdas) y llamar a -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *) para cada celda ralentiza la apertura de una sección, porque cada vez que se lee y se realiza la celda el contenido se está rellenando con la imagen. he visibilidad de verificación de la celda dentro de -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *) como esto:

if ([[self.tableView indexPathsForVisibleRows] containsObject:indexPath]) 
    NSLog(@"visible %@", indexPath); 

y muestra que a partir de 45 células, solamente 6 o 7 son visibles. Otros están fuera del área visible. Pero aún se crean células. Aquí está el código:

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 
static NSString *CellIdentifier = @"IVCell"; 
IVCamera *camera = [server.cameras objectAtIndex:indexPath.row]; 

IVServerListViewCell *cell = (IVServerListViewCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 
if (cell == nil) { 
    [[NSBundle mainBundle] loadNibNamed:@"IVServerListCell" owner:self options:nil]; 
    cell = (IVServerListViewCell*)_tableViewCell; 
    self.tableViewCell = nil; 

} 

[cell textLabel].text = camera.cameraName; 
cell.preview = camera.preview; 
cell.userData = camera; 
cell.isEnabled = (server.isInactive)?NO:camera.isOnline; 

return cell; 
} 

¿Sigue siendo correcta? ¿O me estoy perdiendo algo?

Respuesta

5

Bueno, de alguna forma resolví mi problema. Aquí están mis ideas y pensamientos sobre cómo llegué a la solución. Tal vez podría ser útil para alguien.

He indicado las asignaciones de memoria y la pila de llamadas utilizando instrumentos durante los eventos de la sección de apertura. Me mostró que la mayor parte del tiempo se usa para cargar la celda del archivo de punta.

En primer lugar, he hecho reduciendo el tamaño del archivo nib, es decir, minimizando el número de vistas utilizadas en la tabla personalizada (ahora son solo 2 vistas y 2 etiquetas, en lugar de 6 vistas, 2 imágenes y 2 etiquetas antes). Me dio un poco de mejora en la carga de células. La documentación de Apple sugiere usar el menor número posible de vistas y no usar transparencia. Así que estén atentos a estas sugerencias.

En segundo lugar, como descubrí anteriormente, que no todas las celdas son visibles creadas por -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *), decidí reducir de alguna manera el número de cargas de células nuevas desde el archivo nib. Para lograr esto, he llegado a una idea simple: devolver celdas predeterminadas en blanco para filas invisibles, mientras que cargar celdas personalizadas de plumín para las visibles. Aquí está el trozo de código:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    if ([self index:indexPath isInvisibleInTableView:tableView]) 
     return [self getBlankCellForTableView:tableView]; 

    // the rest of the method is the same 
    ... 
} 

-(BOOL)index:(NSIndexPath*)indexPath isInvisibleInTableView:(UITableView*)tableView 
{ 
    NSMutableArray *visibleIndexPaths = [self getExtendedVisibleIndexPathsForTableView:tableView]; 

    return ![visibleIndexPaths containsObject:indexPath]; 
} 

-(UITableViewCell*)getBlankCellForTableView:(UITableView*)tableView 
{ 
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"IVBlankCell"]; 
    if (!cell) 
     cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"IVBlankCell"] autorelease]; 

    return cell; 
} 

Como se puede ver, no estoy usando sólo -(NSArray*)indexPathsForVisibleRows método de tableview para detectar células visibles. En cambio, escribí mi propio método -(NSMutableArray*)getExtendedVisibleIndexPathsForTableView:(UITableView*)tableView. Fue necesario porque, por alguna razón, al usar -(NSArray*)indexPathsForVisibleRows las celdas que están al lado de la última celda visible o las celdas que están anteriores a la primera celda visible se crearon como celdas en blanco y parecían celdas vacías mientras se desplazaban. Para superar esto, en -(NSMutableArray*)getExtendedVisibleIndexPathsForTableView: (UITableView*)tableView estoy añadiendo células del borde a las celdas de la matriz visibles:

-(NSMutableArray*)getExtendedVisibleIndexPathsForTableView:(UITableView*)tableView{ 
    NSArray *visibleIPs = [tableView indexPathsForVisibleRows]; 

    if (!visibleIPs || ![visibleIPs count]) 
     return [NSMutableArray array]; 

    NSIndexPath *firstVisibleIP = [visibleIPs objectAtIndex:0]; 
    NSIndexPath *lastVisibleIP = [visibleIPs objectAtIndex:[visibleIPs count]-1]; 

    NSIndexPath *prevIndex = ([firstVisibleIP row])?[NSIndexPath indexPathForRow:[firstVisibleIP row]-1 inSection:[firstVisibleIP section]]:nil; 
    NSIndexPath *nextIndex = [NSIndexPath indexPathForRow:[lastVisibleIP row]+1 inSection:[lastVisibleIP section]]; 

    NSMutableArray *exVisibleIndexPaths = [NSMutableArray arrayWithArray:[tableView indexPathsForVisibleRows]]; 

    if (prevIndex) 
     [exVisibleIndexPaths addObject:prevIndex]; 
    [exVisibleIndexPaths addObject:nextIndex]; 

    return exVisibleIndexPaths; 
} 

Por lo tanto, he reducido el tiempo de apertura de las secciones con un gran número de células personalizados, que fue probado por los instrumentos de trazado y sentido al experimentar la aplicación.

+0

que era increíble, yo también tenía un problema como este, su técnica era tan útil que el problema está resuelto. – Ananth

+0

@Ananth eres bienvenido! =) – peetonn

0

Esto parece correcto si. la idea de optimizar la carga está en cómo funciona "dequeueReusableCellWithIdentifier". si está cargando la imagen desde una ubicación remota, aquí es donde desea optimizar el código. pero no desde la carga de las celdas ya que esto parece correcto aquí.

+0

que suena triste. He apagado temporalmente las celdas de población con imágenes, y todavía hay un pequeño retraso molesto para abrir la sección con 42 celdas en comparación con la sección con solo 9 celdas. Creo que esta es la única forma: reducir el tamaño de la punta de la celda personalizada y reducir el número de vistas que se usan en ella. ¿Cómo crees que? – peetonn

+0

Tengo curiosidad sobre cómo está expandiendo/contrayendo las secciones en UITableView. porque eso no está allí por defecto. –

+0

usando 'insertRowsAtIndexPaths: withRowAnimation:' y 'deleteRowsAtIndexPaths: withRowAnimation:' – peetonn

0

Utilicé alguna técnica similar, pero como indexPathsForVisibleRows está ordenado, no es necesario que uses containsObject. En su lugar, puede hacer:

// 
// Checks if indexPath is visible in current scroll state, we are expanding bounds by 1 
// because the cells that are next to the last one visible or the cells that are previous 
// to the first one visible could look empty while scrolling. 
// 
- (BOOL)isIndexPathVisible:(NSIndexPath *)indexPath 
{ 
    NSInteger row = [indexPath row]; 
    NSArray *visible = [self.tableView indexPathsForVisibleRows]; 
    NSInteger count = [visible count]; 
    NSInteger first = (count > 0) ? MAX([visible[0] row] - 1, 0): 0; 
    NSInteger last = (count > 1) ? [visible[1] row] + 1: first + 2; 

    return row >= first && row <= last; 
} 

Por cierto; esto supone que estás usando solo una sección. No funcionará para más de una sección.

0

Agregando un otro problema resuelto. Donde reseteé los cambios que se hicieron en la celda.

if (! self.cell) { 
    self.cell = [[LanguageCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier]; 
    self.cell.accessoryType = UITableViewCellAccessoryNone; 
} 
else 
{ 
    self.cell.checkImage.image = NO; 

} 
2

Compruebe el tamaño de su tabla. puede ser que su altura de la vista de tabla sea muy grande que sigue cargando celdas hasta que su celda llena todo el tamaño de la tabla.

+2

Estaba estableciendo el valor estimadoRowHeight de tableView en un valor bajo de 100pts cuando sabía que todas mis celdas serían de altura> 320pts. Esto estaba causando la carga innecesaria de celdas adicionales hasta 100 + 100 + ...> tableView visible bounds. Luego cambié estimadoRowHeight a 320 y se redujo el número de filas cargadas. – SayeedHussain

Cuestiones relacionadas