2009-09-21 10 views
3

J'ai une base de données SQLite liée à mon uitableview. Il y a environ 2000 lignes, donc je récupère 25 lignes au début. Une fois que je fais défiler jusqu'à la fin de la liste, je veux qu'il récupère automatiquement 25 lignes de plus.Étendre automatiquement UITableView - NSRangeException

Voici la méthode que j'utilise maintenant. Ignorer ce qui se passerait si je charge toutes les 2000 lignes, je m'inquiéterai de cela plus tard. Dans tableView:numberOfRowsInSection: j'en renvoie un de plus que les lignes actuellement chargées. Puis dans tableView:cellForRowAtIndexPath: je charge plus de lignes si elle charge la dernière ligne.

Typiquement, je peux descendre quelques pages, mais je finis par obtenir une exception: *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[NSCFArray objectAtIndex:]: index (10) beyond bounds (10)'. L'index est toujours 8-10. Je ne sais pas de quel tableau il s'agit, mais mes deux matrices rows et indices ont bien plus de 10 éléments.

tableView:cellForRowAtIndexPath:

if(indexPath.row >= [rows count]) { 
    [cell.textLabel setText:@"Loading..."]; 
    if(!updating && indexPath.row == [rows count]) { 
     updating = YES; 
     [[self tableView] beginUpdates]; 
     NSMutableArray *indices = [NSMutableArray array]; 
     // stmt = ... 
     while(sqlite3_step(stmt) == SQLITE_ROW) { 
      [rows addObject:@"..."]; 
      [indices addObject:[NSIndexPath indexPathForRow:[rows count]-1 inSection:0]]; 
     } 
     [[self tableView] insertRowsAtIndexPaths:indices withRowAnimation:UITableViewRowAnimationNone]; 
     [[self tableView] endUpdates]; 
     updating = NO; 
    } 
    return cell; 
} 

Trace de la pile:

#0 0x01ce4004 in ___TERMINATING_DUE_TO_UNCAUGHT_EXCEPTION___() 
#1 0x9779df49 in objc_exception_throw() 
#2 0x01cc5c3b in +[NSException raise:format:arguments:]() 
#3 0x01cc5b9a in +[NSException raise:format:]() 
#4 0x00072cc9 in _NSArrayRaiseBoundException() 
#5 0x00010227 in -[NSCFArray objectAtIndex:]() 
#6 0x0047fe5b in -[_UITableViewUpdateSupport(Private) _setupAnimationsForExistingVisibleCells]() 
#7 0x0047f9e0 in -[_UITableViewUpdateSupport initWithTableView:updateItems:oldRowData:newRowData:oldRowRange:newRowRange:context:]() 
#8 0x002eca2b in -[UITableView(_UITableViewPrivate) _updateWithItems:withOldRowData:oldRowRange:newRowRange:context:]() 
#9 0x002ec757 in -[UITableView(_UITableViewPrivate) _endCellAnimationsWithContext:]() 
#10 0x002def56 in -[UITableView endUpdates]()  

Répondre

4

Je suis un peu difficile de comprendre pourquoi vous insérez des lignes. Il me semble que vous compliquez un peu le processus. UITableView vous demandera seulement des valeurs pour les cellules de tableau qui sont à l'écran (ou le seront bientôt). De plus, en ajoutant continuellement des lignes à la vue de la table, la barre de défilement ne reflète pas la position réelle de l'utilisateur dans l'ensemble de données. Il serait tout aussi logique de retourner le nombre total de lignes dans tableView:numberOfRowsInSection: (vous pouvez utiliser la fonction d'agrégat SQLite COUNT pour ce faire sans réellement récupérer toutes les données) et de mettre en cache des données supplémentaires si nécessaire (en utilisant quelque chose de similaire à ce que vous avez ci-dessus) lorsque vous rencontrez un "miss cache".

Si je devais deviner pourquoi ce code vous causait des problèmes, cependant, ce serait que vous modifiez le contenu de la vue de table alors que la vue de table attend que vous retourniez une cellule.

Je conseillerais quelque chose qui ressemble un peu plus comme ceci:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 
    if ([indexPath row] >= [cache count]) { 
     // Load additional items into the cache 
    } 

    // Do the regular cell setup stuff here; you can assume the data you need is available 
    return cell; 
} 
+1

C'est une excellente solution! Merci beaucoup! – Markus

0

Alex, j'accepte votre réponse, même si je suis toujours intéressé par ce qui cause l'exception réelle. Votre commentaire sur la mise à jour de la table lors du retour d'une cellule m'a amené à implémenter - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath pour charger plus de lignes si nécessaire, ce qui est plus stable, bien que je doive le faire dans un thread séparé pour obtenir toutes sortes de performances.

Votre solution fonctionne également, et elle est certainement plus simple que ma méthode actuelle. Je dois décider si je veux que la barre de défilement affiche la position réelle ou une position plus tangible. Au moins pour moi, on dirait que l'application charge beaucoup d'objets, et donc est plus lente, quand la barre de défilement est si petite.