首页 文章

使用NSFetchedResultsController更新UITableView时,将数据从Web保存到Core Data

提问于
浏览
1

我正在使用HTTP GET方法从Web中提取数据 . 然后我从Web获取JSON数据并将其保存到CoreData中 . 我有一个带有自定义UITableViewCells的UITableView,它使用NSFetchedResultsController进行更新 .

但是当我去保存数据时,tableView只会更新屏幕上的内容,当我向下滚动时,tableView变为白色 .

在日志中,我收到了一些错误:

CoreData:错误:严重的应用程序错误 . 在调用-controllerDidChangeContent:期间,从NSFetchedResultsController的委托中捕获到异常 . 尝试使用userInfo(null)删除并重新加载相同的索引路径({length = 2,path = 0 - 43})

这是我的代码,NSFetchedResultsControllerDelegate在didChangeObject方法中使用:

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.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
        break;

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

我能做什么的想法?

谢谢!

1 回答

  • 0

    那你呢:?

    - (void)controllerWillChangeContent:(NSFetchedResultsController *)controller
    - (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
    

    你可以拿我的,它应该肯定有用,我在几个项目中使用它 . 只需使tableViewController成为子类的子类 . 然后初始化并将fetchedResultsController传递给tableViewController并在其中调用:

    [self setupFetchedResultsController:yourFetchResultsController];
    

    SMCoreDataTableViewController.m:

    #import "SMCoreDataTableViewController.h"
    
    @interface SMCoreDataTableViewController ()
    @property (nonatomic) BOOL beganUpdates;
    @end
    
    @implementation SMCoreDataTableViewController
    
    - (void)performFetch
    {
        if (self.fetchedResultsController) {
            if (self.fetchedResultsController.fetchRequest.predicate) {
                if (self.debug) NSLog(@"[%@ %@] fetching %@ with predicate: %@", NSStringFromClass([self class]), NSStringFromSelector(_cmd), self.fetchedResultsController.fetchRequest.entityName, self.fetchedResultsController.fetchRequest.predicate);
            } else {
                if (self.debug) NSLog(@"[%@ %@] fetching all %@ (i.e., no predicate)", NSStringFromClass([self class]), NSStringFromSelector(_cmd), self.fetchedResultsController.fetchRequest.entityName);
            }
            NSError *error;
            [self.fetchedResultsController performFetch:&error];
            if (error) NSLog(@"[%@ %@] %@ (%@)", NSStringFromClass([self class]), NSStringFromSelector(_cmd), [error localizedDescription], [error localizedFailureReason]);
        } else {
            if (self.debug) NSLog(@"[%@ %@] no NSFetchedResultsController (yet?)", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
        }
        [self.tableView reloadData];
    }
    
    - (void)setupFetchedResultsController:(NSFetchedResultsController *)newfrc
    {
        NSFetchedResultsController *oldfrc = _fetchedResultsController;
        if (newfrc != oldfrc) {
            _fetchedResultsController = newfrc;
            newfrc.delegate = self;
            if ((!self.title || [self.title isEqualToString:oldfrc.fetchRequest.entity.name]) && (!self.navigationController || !self.navigationItem.title)) {
                self.title = newfrc.fetchRequest.entity.name;
            }
            if (newfrc) {
                if (self.debug) NSLog(@"[%@ %@] %@", NSStringFromClass([self class]), NSStringFromSelector(_cmd), oldfrc ? @"updated" : @"set");
                [self performFetch];
            } else {
                if (self.debug) NSLog(@"[%@ %@] reset to nil", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
                [self.tableView reloadData];
            }
        }
    }
    
    #pragma mark - UITableViewDataSource
    
    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
    {
        return [[self.fetchedResultsController sections] count];
    }
    
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    {
        return [[[self.fetchedResultsController sections] objectAtIndex:section] numberOfObjects];
    }
    
    - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
    {
        return [[[self.fetchedResultsController sections] objectAtIndex:section] name];
    }
    
    - (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index
    {
        return [self.fetchedResultsController sectionForSectionIndexTitle:title atIndex:index];
    }
    
    - (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
    {
        return [self.fetchedResultsController sectionIndexTitles];
    }
    
    #pragma mark - NSFetchedResultsControllerDelegate
    
    - (void)controllerWillChangeContent:(NSFetchedResultsController *)controller
    {
        if (!self.suspendAutomaticTrackingOfChangesInManagedObjectContext) {
            [self.tableView beginUpdates];
            self.beganUpdates = YES;
        }
    }
    
    - (void)controller:(NSFetchedResultsController *)controller
      didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
               atIndex:(NSUInteger)sectionIndex
         forChangeType:(NSFetchedResultsChangeType)type
    {
        if (!self.suspendAutomaticTrackingOfChangesInManagedObjectContext)
        {
            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)controller:(NSFetchedResultsController *)controller
       didChangeObject:(id)anObject
           atIndexPath:(NSIndexPath *)indexPath
         forChangeType:(NSFetchedResultsChangeType)type
          newIndexPath:(NSIndexPath *)newIndexPath
    {
        if (!self.suspendAutomaticTrackingOfChangesInManagedObjectContext)
        {
            switch(type)
            {
                case NSFetchedResultsChangeInsert:
                    [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
                    break;
    
                case NSFetchedResultsChangeDelete:
                    [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
                    break;
    
                case NSFetchedResultsChangeUpdate:
                    [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
                    break;
    
                case NSFetchedResultsChangeMove:
                    [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
                    [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
                    break;
            }
        }
    }
    
    - (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
    {
        if (self.beganUpdates) [self.tableView endUpdates];
    }
    
    - (void)endSuspensionOfUpdatesDueToContextChanges
    {
        _suspendAutomaticTrackingOfChangesInManagedObjectContext = NO;
    }
    
    - (void)setSuspendAutomaticTrackingOfChangesInManagedObjectContext:(BOOL)suspend
    {
        if (suspend) {
            _suspendAutomaticTrackingOfChangesInManagedObjectContext = YES;
        } else {
            [self performSelector:@selector(endSuspensionOfUpdatesDueToContextChanges) withObject:0 afterDelay:0];
        }
    }
    
    @end
    

    SMCoreDataTableViewController.h:

    #import <UIKit/UIKit.h>
    #import <CoreData/CoreData.h>
    
    @interface SMCoreDataTableViewController : UITableViewController <NSFetchedResultsControllerDelegate>
    
    @property (strong, nonatomic) NSFetchedResultsController *fetchedResultsController;
    
    @property (nonatomic) BOOL suspendAutomaticTrackingOfChangesInManagedObjectContext;
    @property BOOL debug;
    
    - (void)setupFetchedResultsController:(NSFetchedResultsController *)fetchedResultsController;
    
    @end
    

相关问题