2014-12-18 22 views
0

我正在更新单元格上的下载视图/按钮,当我去更新我的单元格时,我没有得到正确的部分。NSFetchedResultsController indexPathForObject不计算节

我的代码来获取指数和更新下载进度是这样的:

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

你如何更新细胞?你通常不需要调用'cellForRow ...'来做到这一点。 – 2014-12-18 22:22:50

+0

这只是为了获得与我收到通知的对象相匹配的单元格。我不刷新单元格,只是单元格中的一个视图。 – Siriss 2014-12-18 22:51:25

+0

请您发帖说1)初始化FRC的代码,2)表视图数据源方法,以及3)FRC委托方法? – pbasdf 2014-12-19 00:02:58

回答

1

更新细胞这种方式是不可靠的。以这种方式更新的单元迟早会被重新使用。根据数据源提供的数据,单元格的子视图将被tableView:cellForRowAtIndexPath:重新配置。

您应该对Object本身进行更改(而不是将它们传递给通知的userInfo)并保存管理的对象上下文。然后NSFetchedResultsControllerDelegate回调将触发,允许您重新加载相应的行。那么你应该在configureCell:atIndexPath中设置MyTableViewCell的所有属性。

而且configureCell:方法应该被称为从cellForRowAtIndexPath方法,而不是从获取的成果控制器的委托方法。一般模式是在controllerDidChangeObject:中拨打reloadRowsAtIndexPaths:。否则,你可能会遇到一些单元重用问题。

的代码看起来应该像一个想法:

- (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; 

最后,配置(假设您从tableView:cellForRowAtIndexPath:拨打configureCell:atIndexPath):

- (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 
}