所以多年来我一直在做以下操作来访问我的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?
答案 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;;