NSArrayController,以编程方式创建Core Data实体,以及KVO

时间:2013-04-11 07:43:16

标签: cocoa core-data cocoa-bindings key-value-observing

我有一个NSTableView,其NSTableColumn的值绑定到NSArrayController。 arrayController控制核心数据管理对象上下文中的一组实体。

效果很好,当通过UI操作将新实体插入arrayController时,tableView会选择新项目。

但是我会以编程方式在moc中创建新实体,然后在arrayController中选择新对象。

我尝试了以下内容:

Image *newImage = [Image newImage]; // convenience method to insert new entity into mod.
newImage.title = [[pathToImage lastPathComponent] stringByDeletingPathExtension];
newImage.filename = [pathToImage lastPathComponent];

[self.primaryWindowController showImage:newImage];

showImage:方法如下:

- (void)showImage:(Image *)image
{
    [self.imagesArrayController fetch:self];
    [self.imagesArrayController setSelectedObjects:@[image]];
}

但是,arrayController不会更改其选择。

我做错了吗?我假设我在moc中创建的newImage对象与arrayController控制的对象相同。如果这是真的,为什么arrayController不改变它的选择?

嗯 - 测试这个假设,我现在已经在运行时检查了arrayController的内容。新图像不存在 - 我认为这意味着我已经通过手动插入moc而“落后于绑定”......

我的newImage便捷方法如下:

+ (Image *)newImage
{
    Image *newImage = [NSEntityDescription insertNewObjectForEntityForName:@"Image" inManagedObjectContext:[[CoreDataController sharedController] managedObjectContext]];
    return newImage;
}

这不符合KVO吗?

嗯 - 编辑2 ...

我认为它符合KVO,因为新图像出现在UI中。我现在认为在将实体插入moc和通知arrayController之间存在延迟。

我从这个问题看到New Core Data object doesn't show up in NSArrayController arrangedObjects(有问题地显示在SO的这个问题的右侧),要求arrayController获取:应该帮助更新arrayController,但是实际的fetch:才会发生下次runloop运行。

我应该使用计时器延迟选择新对象吗?这似乎有点不雅......

2 个答案:

答案 0 :(得分:2)

正确 - 由于这个问题解决了它:New Core Data object doesn't show up in NSArrayController arrangedObjects

我必须在插入新对象后直接在moc上调用processPendingChanges:

所以,我的新创作便利方法现在是:

+ (Image *)newImage
{
    Image *newImage = [NSEntityDescription insertNewObjectForEntityForName:@"Image" inManagedObjectContext:[[CoreDataController sharedController] managedObjectContext]];
    [[[CoreDataController sharedController] managedObjectContext] processPendingChanges];
    return newImage;
}

答案 1 :(得分:0)

如果您想以编程方式执行此操作,最简单的方法是直接将新实体对象添加到NSArrayController,就像这样简单:

[self.imagesArrayController addObject:newImage];

这将完成将对象添加到控制器并选择它的技巧。

虽然有一个小故障 - 我不知道您使用什么视图(NSView,UIView)来呈现NSArrayController的内容 - 但是NSTableView不会自动滚动显示新添加的项目。

我不得不推迟这个(因为添加发生在后来的一些runloop中),如此:

    NSUndoManager *um = self.managedObjectContext.undoManager;
[um beginUndoGrouping];
[um setActionName:NSLocalizedString(@"New Sample", NULL)];
PMWaterSample *sampleToAdd = [self createNewSample];
[self.samplesController addObject:sampleToAdd];

// Actual addition is deferred, hence we delay the scrolling too, on the main-thread's queue.
dispatch_async(dispatch_get_main_queue(), ^{
    [self.samplesController rearrangeObjects];

    // bring last row (newly added) into view
    NSUInteger selectedIdx = [self.samplesController selectionIndex];
    if (selectedIdx != NSNotFound) {
        [self.samplesTable scrollRowToVisible:selectedIdx];
    }
    [um endUndoGrouping];
});

希望这会有所帮助。我从来没有强迫MOC处理PendingChanges。我仍然感觉有更好的方法来做到这一点,并让阵列控制器使其嵌入的UI元素滚动并显示新项目,但我不知道如何。