2014-12-18 25 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 
}