NSFetchedResultsController在启动后不会更新UITableView

时间:2013-10-16 02:40:02

标签: iphone ios objective-c uitableview nsfetchedresultscontroller

我有一个简单的基于UIManagedDocument的Core Data应用程序。我是iOS新手编程的新手,我几乎没有把它搞定,而且我被卡住了。我有人NSManagedObjects存储在Core Data中。当我第一次启动应用程序时,没有任何条目,但如果我向上滑动一个模态VC并将其关闭,它们会神奇地出现。我的设计松散地基于iTunes U / Sanford课程中的“Photomania”应用程序,但使用单个CoreDataStore对象来处理获取managedObjectContext。这是我的CoreDataStore的代码:

+ (CoreDataStore *)sharedStore
{
    static CoreDataStore *sharedStore = nil;
    if (!sharedStore)
        sharedStore = [[super allocWithZone:nil] init];

    return sharedStore;
}

+ (instancetype)allocWithZone:(struct _NSZone *)zone
{
    return [self sharedStore];
}

- (NSManagedObjectContext *)getContext
{
    NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory
                                                         inDomains:NSUserDomainMask] lastObject];
    url = [url URLByAppendingPathComponent:@"dbDocument"];
    UIManagedDocument *document = [[UIManagedDocument alloc] initWithFileURL:url];

    if (![[NSFileManager defaultManager] fileExistsAtPath:[url path]]) {
        NSLog(@"No file exists...");
        [document saveToURL:url forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success) {
            NSLog(@"Document saveForCreating completionHandler invoked. Success: %hhd", success);
            if (success) {
                self.managedObjectContext = document.managedObjectContext;
                NSLog(@"Got context for created file!!");
            }
        }];
    } else if (document.documentState == UIDocumentStateClosed) {
        NSLog(@"Document state is closed. documentState == %u", document.documentState);
        [document openWithCompletionHandler:^(BOOL success) {
            NSLog(@"Document opening success: %hhd", success);
            if (success) {
                self.managedObjectContext = document.managedObjectContext;
                NSLog(@"Got context for now-opened file!!");
            }
        }];
    } else {
        self.managedObjectContext = document.managedObjectContext;
        NSLog(@"Got context for already-opened file!!");
    }

    return self.managedObjectContext;
}

以下是PeopleListViewController的代码:

- (void)setManagedObjectContext:(NSManagedObjectContext *)managedObjectContext
{
    _managedObjectContext = managedObjectContext;
    if (managedObjectContext) {
        NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Person"];
        request.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"name"
                                        ascending:YES
                                        selector:@selector(localizedCaseInsensitiveCompare:)]];
        request.predicate = nil;  // all Persons
        self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:nil];
    } else {
        self.fetchedResultsController = nil;
    }
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    if (!self.managedObjectContext)
        [self setManagedObjectContext:[[CoreDataStore sharedStore] getContext]];
}

这是发布后的结果:

After launch

这是模态VC:

Modal VC

这是在解雇模态VC(点击取消)之后:

After Modal

我已经尝试在managedObjectContext上使用performFetch,甚至将它延迟到核心数据文档报告它被打开之后。什么都行不通。任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:0)

从粗略看一下你的代码,我注意到你是异步创建你的上下文。这很好,但是当上下文准备就绪时,您需要通知表视图控制器并让它调用reloadData。

数据存储中的完成处理程序需要在表视图控制器上设置context属性。

答案 1 :(得分:0)

NSFetchedResultsController并没有神奇地更新你的tableView。我发现Photomania有点复杂,因为很少有像CoreDataViewController那样的助手类。因此,只能通过调用reloadData方法或使用beginUpdates - endUpdates对来重新加载tableVew。并且NSFetchedResultsController只能通过调用performFetch:方法进行更新。 我通常使用NSManagedObjectContext getter:

- (NSFetchedResultsController*)fetchedResultsController
{
    if (!_fetchedResultsController)
    {
        NSFetchRequest* fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"some entity name"];
        fetchRequest.predicate = [NSPredicate predicateWithFormat:@"some predicate"];
        fetchRequest.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES]];
        _fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.context sectionNameKeyPath:@"name" cacheName:nil];
        _fetchedResultsController.delegate = self;
        NSError* error;
        [_fetchedResultsController performFetch:&error];
        if (error)
        {
            NSLog(@"Fetch ERROR. %@", error);
        }
    }
    return _fetchedResultsController;
}

在这里,我将NSFetechedResultsControllerDelegate设置为自我。并performFetch:获取数据。我意识到委托的方法:

- (void)controllerWillChangeContent:(NSFetchedResultsController*)controller
{
    [self.tableView beginUpdates];
}

- (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)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:[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];
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
                             withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}

- (void)controllerDidChangeContent:(NSFetchedResultsController*)controller
{
    [self.tableView endUpdates];
}