Обновление и удаление содержимого в фоновом потоке ошибок (NSFetchedResultsController) - PullRequest
0 голосов
/ 24 августа 2010

Я использую NSFetchedResultsController для заполнения содержимого моего UITableViewController.

Я использую NSOperation для сбора данных из веб-службы (я использую отдельный ManagedObjectContext, поскольку это другой поток)
Когда данные сохранены, вызывается мой ViewController (который является NSFetchedResultsControllerDelegate), и я объединяю свои MOC, используя mergeChangesFromContextDidSaveNotification

#pragma mark -
#pragma mark Parsers delegate

- (void)parserWillSave:(id)parser{
    TopNewsParser *emp = (TopNewsParser *)parser;
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(parserContextDidSave:) name:NSManagedObjectContextDidSaveNotification object:emp.managedObjectContext];
    [NSFetchedResultsController deleteCacheWithName:@"aLaUne"];
}

- (void)parserDidSave:(id)parser{
    TopNewsParser *emp = (TopNewsParser *)parser;
    [[NSNotificationCenter defaultCenter] removeObserver:self name:NSManagedObjectContextDidSaveNotification object:emp.managedObjectContext];
}

/**
 Notification from the add controller's context's save operation. This is used to update the fetched results controller's managed object context with the new book instead of performing a fetch (which would be a much more computationally expensive operation).
 */
- (void)parserContextDidSave:(NSNotification*)saveNotification {
    DLog(@"");
    NSManagedObjectContext *fetchContext = [_fetchedResultsController managedObjectContext];
    // Merging changes causes the fetched results controller to update its results
    [fetchContext performSelectorOnMainThread:@selector(mergeChangesFromContextDidSaveNotification:)
                                  withObject:saveNotification
                               waitUntilDone:YES]; 


}

Для NSFetchedResultsControllerDelegate я использую код из образца CoreData Books

#pragma mark -
#pragma mark NSFetchedResultsControllerDelegate

- (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 {
    //ALog(@"indexPath: %@ newIndexPath : %@ | type : %d # %@",indexPath,newIndexPath,type,anObject);
    UITableView *tableView = self.tableView;

    switch(type) {

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

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

        case NSFetchedResultsChangeUpdate:
            [self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
            break;

        case NSFetchedResultsChangeMove:
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
            // Reloading the section inserts a new row and ensures that titles are updated appropriately.
            [tableView reloadSections:[NSIndexSet indexSetWithIndex:newIndexPath.section] withRowAnimation:UITableViewRowAnimationFade];
            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:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeDelete:
            [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}


- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
    UIBarButtonItem *reloadButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh 
                                                                                  target:self                               
                                                                                  action:@selector(refreshTableViewContent)];
    reloadButton.accessibilityLabel = @"Reload";
    self.navigationItem.leftBarButtonItem = reloadButton;

    // The fetch controller has sent all current change notifications, so tell the table view to process all updates.
    [self.tableView endUpdates];

}

Моя проблема в том, что при загрузке нового контента, где какой-то объект был удален, мой tableView испортился! Строка все еще видна, даже если мой countOfRow уменьшен на 1:

Затем, когда я прокручиваю вниз, мое табличное представление пусто (только 4 видимые строки) все еще находятся в табличном представлении, иначе это пустой scrollView

В консоли я вижу следующее сообщение.

Серьезная ошибка приложения. Исключение было получено от делегата NSFetchedResultsController во время вызова -controllerDidChangeContent :. *** - [NSMutableArray removeObjectAtIndex:]: индекс 0 вне границ для пустого массива с userInfo (null)

Вначале я думал, что это связано с кэшем моего NSFetchedResultsController, но даже когда я его отключаю, у меня возникает та же проблема.

У кого-нибудь есть идеи, как это исправить?

1 Ответ

0 голосов
/ 14 февраля 2011

Та же проблема здесь.

Люди предложили использовать пример кода TopSongs. Модифицированная версия здесь: http://www.bigbluebrains.com/index.php/2010/08/16/iphone-topsongs-sample-code-memory-leak-fix/

Интересно, должны ли мы использовать мьютекс для общих данных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...