我正在更新单元格上的下载视图/按钮,当我去更新我的单元格时,我没有得到正确的部分。
获取索引并更新下载进度的代码是:
Object *obj = (Object *)notification.object;
NSIndexPath *index = [self.fetchedResultsController indexPathForObject:obj];
MyTableViewCell *cell = (MyTableViewCell *)[self.tableView cellForRowAtIndexPath:index];
DownloadProgressButtonView *buttonView = (DownloadProgressButtonView *)cell.accessoryView;
NSNumber *progressLong = [notification.userInfo objectForKey:@"progress"];
float progress = [progressLong floatValue];
NSNumber *totalBytesLong = [notification.userInfo objectForKey:@"totalBytes"];
float totalBytes = [totalBytesLong floatValue];
buttonView.progress = progress *.01;
float totalDownloadEstimate = totalBytes / 1.0e6;
float megaBytesDownloaded = (progress *.01) * totalDownloadEstimate;
cell.bottomLabel.text = [NSString stringWithFormat:@"%.1f MB of %.1f MB", megaBytesDownloaded, totalDownloadEstimate];
如果我有两个对象,每个对象在不同的部分,则它们具有相同的行(0)。当我去更新我的单元格时,它会更新第1部分中的单元格而不是第0部分。如何修复此问题?
我可以放任何其他需要的代码。如果我只是在我的NSFetchedResultsController中禁用部分,它可以完美地工作。
我的NSFetchedResultsController和委托。
- (NSFetchedResultsController *)fetchedResultsController
{
if (_fetchedResultsController != nil) {
return _fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Object" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
NSSortDescriptor *nameString = [[NSSortDescriptor alloc] initWithKey:self.sectionSortDescriptor ascending:NO];
NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:self.sortDescriptor ascending:YES];
[fetchRequest setSortDescriptors:[NSArray arrayWithObjects:nameString,descriptor, nil]];
NSString *downloadStartedString = @"Preparing to download";
NSString *downloadingString = @"Downloading";
NSString *downloadPausedString = @"Download paused";
fetchRequest.predicate = [NSPredicate predicateWithFormat:@"(downloaded == YES) OR (downloadStatus like[cd] %@) OR (downloadStatus like[cd] %@) OR (downloadStatus like[cd]%@)",downloadPausedString, downloadStartedString,downloadingString];
[fetchRequest setFetchBatchSize:20];
_fetchedResultsController =
[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:self.managedObjectContext sectionNameKeyPath:self.sectionNameString
cacheName:nil];
_fetchedResultsController.delegate = self;
self.fetchedResultsController = _fetchedResultsController;
return _fetchedResultsController;
}
/*
NSFetchedResultsController delegate methods to respond to additions, removals and so on.
*/
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
// The fetch controller is about to start sending change notifications, so prepare the table view for updates.
[self.tableView beginUpdates];
}
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath
{
UITableView *tableView = self.tableView;
switch(type)
{
case NSFetchedResultsChangeInsert:
[tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
break;
case NSFetchedResultsChangeDelete:
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
break;
case NSFetchedResultsChangeUpdate:
[self configureCell:(StudioTableViewCell *)[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
break;
case NSFetchedResultsChangeMove:
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
[tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
break;
}
}
- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type
{
switch(type)
{
case NSFetchedResultsChangeInsert:
[self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationAutomatic];
break;
case NSFetchedResultsChangeDelete:
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationAutomatic];
break;
case NSFetchedResultsChangeMove:
NSLog(@"A table item was moved");
break;
case NSFetchedResultsChangeUpdate:
NSLog(@"A table item was updated");
break;
}
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
// The fetch controller has sent all current change notifications, so tell the table view to process all updates.
[self.tableView endUpdates];
}
最后,当下载状态发生变化时,我会更新对象并发送通知以更新具有新状态的单元格:
- (void)updateCell:(NSNotification *)notification
{
Object *obj = (Object *)notification.object;
NSIndexPath *index = [self.fetchedResultsController indexPathForObject:obj];
[self.tableView reloadRowsAtIndexPaths:@[index] withRowAnimation:UITableViewRowAnimationFade];
}
答案 0 :(得分:1)
以这种方式更新单元格并不可靠。以这种方式更新的单元格迟早会被重用。根据数据源提供的数据,tableView:cellForRowAtIndexPath:
将重新配置单元格的子视图。
您应该对Object
本身进行更改(而不是在通知&#39; userInfo
中传递它们)并保存托管对象上下文。然后将触发NSFetchedResultsControllerDelegate
回调,允许您重新加载相应的行。然后,您应该在MyTableViewCell
中设置configureCell:atIndexPath
的所有属性。
configureCell:
方法应该从cellForRowAtIndexPath
方法调用,而不是从获取的结果控制器委托方法调用。一般模式是在reloadRowsAtIndexPaths:
中调用controllerDidChangeObject:
。否则,您可能会遇到一些细胞重用问题。
关于代码应该如何的想法:
- (void)updateCell:(NSNotification *)notification
{
//depending on your Core Data contexts setup,
// you may need embed the code below in performBlock: on object's context,
// I omitted it for clarity
Object *obj = (Object *)notification.object;
//save changes to the object, for example:
NSNumber *progressLong = [notification.userInfo objectForKey:@"progress"];
obj.progress = progressLong;
//set all the properties you will need in configureCell:, then save context
[obj.magagedObjectContext save:&someError];
}
然后获取的结果控制器将调用controllerDidChangeObject:
,在这种方法中你应该重新加载行:
case NSFetchedResultsChangeUpdate:
[self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
break;
最后,配置单元格(让我们假设您从configureCell:atIndexPath
拨打tableView:cellForRowAtIndexPath:
):
- (void)configureCell:(MyTableViewCell*)cell atIndexPath:(NSIndexPath*)indexPath {
Object *object = [self.fetchedResultsController objectAtIndexPath:indexPath];
DownloadProgressButtonView *buttonView = (DownloadProgressButtonView*) cell.accessoryView;
buttonView.progress = object.progress.floatValue *.01;
//and so on
}