0

我有一个简单的基于 UIManagedDocument 的核心数据应用程序。我是在 iOS 中编程的新手,我几乎没有开始使用它,我被困住了。我将 People NSManagedObjects 存储在核心数据中。当我第一次启动应用程序时,那里没有任何条目,但是如果我向上滑动一个模态 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]];
}

这是启动后立即出现的结果:

发射后

这是模态VC:

模态VC

这是在关闭模态 VC 之后(点击取消):

后模态

我尝试在 managedObjectContext 上使用 performFetch,甚至将其延迟到 Core Data 文档报告它已打开之后。没有任何效果。任何帮助将不胜感激。

4

2 回答 2

0

NSFetchedResultsController不会神奇地更新您的 tableView。我发现 Photomania 有点复杂,因为像 CoreDataViewController 这样的辅助类很少。所以 tableVew 只能通过调用reloadData方法或使用一对beginUpdates-来重新加载endUpdates。并且NSFetchedResultsController只能通过调用performFetch:方法来更新。我通常使用NSManagedObjectContext吸气剂:

- (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];
}
于 2013-10-16T02:54:05.680 回答
0

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

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

于 2013-10-16T02:50:56.003 回答