Thursday, April 12, 2012

Reloading UITableView without animation

What I'm trying to achive is UITableView reloading fast. Each cell has "checking" UIButton wchich tells user that item for this cell is selected. All selected cells should be on the end of the list (bottom cells).



I'm using NSFetchResultsController as a delegate and data source for UITableView. NSFetchResultsController is set to operate with "Item" entity with sectionKey selected for "checked" property (part od "Item" entity which )



- (id)initWithItemView:(ItemView*)iv{
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Item" inManagedObjectContext:[CoreDataHandler context]];
[request setEntity:entity];
NSArray *predicates = [NSArray arrayWithObjects:[iv listDBUsingContext:[CoreDataHandler context]],nil];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"lista IN %@ AND deletedDB == NO", predicates];
[request setPredicate:predicate];
[request setFetchBatchSize:20];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"checked" ascending:YES selector:@selector(compare:)];
NSSortDescriptor *sortDescriptor2
= [[NSSortDescriptor alloc] initWithKey:@"position" ascending:YES selector:@selector(compare:)];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, sortDescriptor2, nil];
[request setSortDescriptors:sortDescriptors];
[sortDescriptors release];
[sortDescriptor release];
[sortDescriptor2 release];
if (self=[[FastTableDelegate alloc]
initWithFetchRequest:request
managedObjectContext:[CoreDataHandler context]
sectionNameKeyPath:@"checked"
cacheName:nil])
{
self.delegate = self;
self.itemView = iv;
self.heightsCache = [NSMutableDictionary dictionary];
}
[request release];
[self performFetch:nil];
return self;
}


Then when the user tap UIButton in cell I change the "checked" property in NSmanagedObject (Item entity) and save the context. Then my NSFetchReslutsController is notified that one item changed it state and it performs UITableView reload using functions



- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath {

UITableView *tableView = self.itemView.tableView;
switch(type) {

case NSFetchedResultsChangeInsert:
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
withRowAnimation:UITableViewRowAnimationNone];
break;

case NSFetchedResultsChangeDelete:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationNone];
break;

case NSFetchedResultsChangeUpdate:
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationNone];
break;

case NSFetchedResultsChangeMove:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationNone];
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
withRowAnimation:UITableViewRowAnimationNone];
break;
}
}


Because I changed "checked" property which is sectionKey for my NSFetchedResultsController UITableView should be reloaded with this scenario



case NSFetchedResultsChangeMove:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationNone];
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
withRowAnimation:UITableViewRowAnimationNone];
break;


And here is a problem because when cells are inserted or delated UITableView performs animation which duration is about 0.5s. In this time UITableView stop reciving events for next cell so when the user "check" another cell it will not be notified about that tap. What I'm trying to achive is to enable user to quick checking some cells without waiting for animation to end.



Possible solutions:




  1. Use reloadData istead of deleteRowsAtIndexPaths/insertRowsAtIndexPaths. It will be no animation but reloading all UITableView last longer that reloading one cell so in my case user will wait for UITableView to reload - again waiting. IS there a way to avoid animation without reloading all UITableView?


  2. Enable user to check cells, but save context only after 0.5s after last cell selection. User can select fast multiple cell and when he ends selecting all changes are propagated to UITableView - my boss want to send each selected cell to second section without grouping then, one reload for each cell selected - again bad idea


  3. Maybe some custom tableView (user created, not apple) ?




Primary goal:



Enable user to "check" cells quickly refreshing UITableView after each "checking"



I'm open for any ideals :)





No comments:

Post a Comment