如果必须仅从主线程使用UIApplication.delegate,如何访问managedObjectContext?

时间:2018-04-20 03:03:12

标签: swift core-data

所以多年来我一直在做以下操作来访问我的managedObjectContext的通用实例。

let managedObjectContext = (UIApplication.shared.delegate as! AppDelegate).managedObjectContext

现在,当我想在后台线程上进行一些CoreData工作时,我会执行以下操作:

let privateContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
                privateContext.persistentStoreCoordinator = (UIApplication.shared.delegate as! AppDelegate).managedObjectContext!.persistentStoreCoordinator
                privateContext.perform { //Do work

好吧,我现在在Swift 4中收到以下错误。

  

UIApplication.delegate必须仅在主线程中使用

重点是在后台线程上完成工作,现在最好的做法是什么?为我的后台线程创建一个新的managedObjectContext?

3 个答案:

答案 0 :(得分:1)

如果要在单独的线程上执行Core Data,则每个线程都应该有一个单独的托管对象上下文。请参阅Core Data Concurrency docs使用专用队列支持并发部分。请务必设置其parentContext

let privateMOC = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType)
privateMOC.parentContext = moc

这有助于确保数据完整性。有一些警告。这是NSManagedObjectContext docs父商店部分中最重要的部分:

  

在上下文中保存更改时,更改仅提交“一个存储”。如果保存子上下文,则更改将推送到其父级。在保存根上下文之前,更改不会保存到持久性存储中。 (根管理对象上下文是其父上下文为nil的上下文。)此外,父项在保存之前不会从子项中提取更改。如果您希望最终提交更改,则必须保存子上下文。

就存储位置而言 - 它可以是任何有意义的对象上的任何位置,但是避免将其存储在UIKit对象上以避免主线程警告。

答案 1 :(得分:1)

实际上您的错误似乎与核心数据无关。我想你只是在后台线程上调用UIApplication.shared.delegate。一个更好的解决方案可能是将Core Data的东西从App Delegate中取出(在另一个单例中,或者更好,通过控制器传递上下文)。

关于核心数据堆栈,您的解决方案似乎是最好的。最好在直接连接到协调器的私有上下文上执行后台工作。但是,如果需要,您必须处理managedObjectContextDidSave通知以更新主要上下文:

[私人]→[协调员]←[主要]

另一个选择是使主要上下文成为私有上下文的子项:

[协调员]←[私人]←[主要]

最后一个并不是很有趣,因为获取/保存操作将通过主上下文然后阻止UI。

[协调员]←[主要]←[私人]

答案 2 :(得分:-1)

在后台线程中,您可以向主队列添加操作。

例如:

SELECT a.id,b.size,c.item_no,d.size_id 
FROM inv a LEFT JOIN product b ON a.id=b.id 
LEFT JOIN all_products c ON a.id=c.id and a.size=c.size 
LEFT JOIN 
  (SELECT qty, code, code2,status FROM prod_stock where status='1')    
  AS d ON c.web_code=d.code 
LEFT JOIN prod_size e ON a.size_id=e.prod_size_id 
WHERE a.id='123456' ORDER BY a.id,e.prod_size_id;;