核心数据:使用新创建的 ManagedObject 转至细节控制器
Posted
技术标签:
【中文标题】核心数据:使用新创建的 ManagedObject 转至细节控制器【英文标题】:Core Data: Segue to detail controller with newly created ManagedObject 【发布时间】:2017-06-12 09:19:36 【问题描述】:情况
-
用户点击按钮将项目添加到表格视图中。
表格视图控制器将项目和segues 直接添加到编辑/详细视图控制器。
项目是用NSFetchedResultsController
填充的核心数据对象。
问题
如何获得对新对象的有效引用以便执行转场?我正在寻找通用模式,而不是违反任何核心数据规则。
代码
class MasterViewController: UITableViewController, NSFetchedResultsControllerDelegate
var context: NSManagedObjectContext!
var frc: NSFetchedResultsController! // set up fetch request etc.
// User initiated
func addItem(_ sender: Any)
context.perform
let item = Item(context: context)
try! context.save()
// How to get hold of the new item and where to initiate the segue?
func prepare(for segue: UIStoryboardSegue, sender: Any)
// Pass new item to detail view controller
// NSFetchedResultsControllerDelegate methods
// refresh table on updates
想法
1) 假设context
是主视图上下文这样安全且正确吗?
var newItem: Item?
func addItem(_ sender: Any)
context.perform
newItem = Item(context: context)
try! context.save() // error handling etc.
performSegue(...)
func prepare(for segue: UIStoryboardSegue, sender: Any)
// ...
detailController.item = newItem
perform 块将在上下文队列中执行,该队列是主队列,这将使从闭包中抓取对象并安全地进行 segue,对吗?
2) 还是这个?
context.performAndWait
newItem = Item(context: context)
try! context.save()
performSegue(...)
对于 1) 和 2):如果这不是主要上下文怎么办?我可以将对象传输到主线程/视图控制器吗?
3) 在 FRC 委托中抓取对象:
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?)
// Assuming insert
new Item = object
performSegue(...)
我怎么知道object
是我刚刚插入并想要继续的那个,而不仅仅是通过其他方式插入的某个对象?我可以确定当我插入一个对象时,下一次调用委托方法将引用该对象吗?可能存在插入元素的并行上下文...
参考
我正在尝试重新创建没有核心数据的基本设置:
class MasterViewController: UITableViewController
var tableViewData = [Item]()
let newItem: Item?
// On user button press
func addItem(_ sender: Any)
newItem = Item()
tableViewData.append(newItem)
tableView.reloadData()
performSegue(withIdentifier: "showDetail")
func prepare(for segue: UIStoryboardSegue, sender: Any)
// ...
detailController.item = newItem
【问题讨论】:
【参考方案1】:在我看来,这可能更清楚:
//On user button press
func addItem()
performSegue(withIdentifier: "showDetail")
func prepare(for segue: UIStoryBoardSegue, sender: Any)
if segue.identifier == "showDetail"
//create the item(managedobject), save the context
//feed the item to the destination viewcontroller who needs it
这样你就知道你所使用的对象是正确的,并且你的逻辑更紧密。
参考上下文。当你创建一个 managedObjectContext 时,你指定你将如何使用它(主要的或私有的),你必须坚持这一点。最好有一个上下文,即您向下传递视图控制器层次结构。
当您开始考虑将设备上的数据与后端数据库同步时,您可能需要第二个上下文,我认为目前还不是这样。 您可能希望将第二个上下文设为私有队列,然后才需要担心将托管对象映射到正确的上下文。
在那之前,你唯一的背景是一种非常友好的动物。
【讨论】:
谢谢!因此,如果我只处理主要上下文,则无需使用context.perform
块包装?从 SO 得到相互矛盾的答案,现在开始阅读 objc.io 核心数据书。他们提到即使在主要上下文中使用perform
并且仅对来自更改通知(例如 FetchedResultsController 或自定义通知)的更改做出反应,而不是将对象转移出块是一个好习惯。我发现事件和更改通知之间的这种脱节相当令人困惑。我如何知道更改是由用户发起的,而不是其他一些后台工作(例如同步)?
是的,这是个好习惯,我也有。但这不是强制性的。实际上,在这种情况下,您必须小心不要将 insert 包装在 performBlock 中,因为 performBlock 是异步的,您需要立即引用新创建的 managedObject。但是您仍然可以将上下文保存在 performBlock 中(这就是我所做的)。关于另一个好习惯,即仅通过合并它们的保存通知来在上下文之间进行通信,它是如此真实,它带来了如此多的清晰度。但是,如果你真的需要,你也可以改掉这个好习惯。以上是关于核心数据:使用新创建的 ManagedObject 转至细节控制器的主要内容,如果未能解决你的问题,请参考以下文章
在 SwiftUI NaviagationLink 中创建 ManagedObject
iPad --- [self.tableViewSection reloadData] 时的 managedObject 问题
ManagedObject 和 ObservedObject
controllerDidChangeContent:每次在 Core Data 中创建 ManagedObject 时调用
managedObject 上的 setValuesForKeysWithDictionary 在 swift 中给出编译错误