NSArrayController,以编程方式创建 CoreData 实体,以及 KVO
Posted
技术标签:
【中文标题】NSArrayController,以编程方式创建 CoreData 实体,以及 KVO【英文标题】:NSArrayController, creating CoreData entities programmatically, and KVO 【发布时间】:2013-04-11 07:43:15 【问题描述】:我有一个 NSTableView,其 NSTableColumn 的值绑定到一个 NSArrayController。 arrayController 控制我的核心数据托管对象上下文中的一组实体。
效果很好,当新实体通过 UI Actions 插入到 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 中看到(帮助显示在这个问题的右侧),要求 arrayController 获取:应该有助于更新 arrayController,但实际获取:直到下一次才会发生运行循环运行。
我应该使用计时器延迟选择新对象吗?这似乎有点不雅......
【问题讨论】:
【参考方案1】:正确 - 解决了,感谢这个问题: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;
【讨论】:
哇,你有一个coreDataController sharedController]
课程正在进行。几乎就像一个单例类,如果你不介意,你能分享一下你在 git 存储库中拥有的 CoreDataController 类吗?这对像我这样的人和许多正在进入 Core Data 的人非常有帮助。看一个实际的例子会很有帮助。谢谢迪戈里
实际上不需要这样的“coreDataController”,因为 CoreData API 非常清晰,而且您在应用程序的很多地方都使用它们,将 CoreData 调用集中到一个特定的控制器是没有意义的.此外 - 在上面的示例中,更好的实现是从新实体本身获取 managedObjectContext - 而不是来自上下文可能不同的某个不同的控制器。 (例如,在基于文档的应用程序中,文档窗口控制器有一个 mangedObjectContext)【参考方案2】:
如果你想以编程方式进行,最简单的方法是直接将新的实体对象添加到 NSArrayController 中,简单如下:
[self.imagesArrayController addObject:newImage];
这将完成将对象添加到控制器并选择它的技巧。
虽然有一个小故障 - 我不知道您使用什么视图(NSView、UIView)来呈现 NSArrayController 的内容 - 但 NSTableView 不会自动滚动以显示新添加的项目。
我不得不推迟这个(因为添加发生在以后的一些运行循环中),如下所示:
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 元素滚动并显示新项目,但我不知道如何。
【讨论】:
以上是关于NSArrayController,以编程方式创建 CoreData 实体,以及 KVO的主要内容,如果未能解决你的问题,请参考以下文章
遍历 NSTableview 或 NSArrayController 以获取数据
NSArrayController 创建、修改然后选择一个新对象