我的应用程序在运行时可能会创建/删除数千个托管对象。我使用NSPrivateQueueConcurrencyType
和NSOperation
秒的次要NSManagedObjectContext
s(MOC),以使应用程序更具响应能力,并且大多数零件都能正常工作。但是当我按下⌘Q并且未保存的对象数量很大时,应用程序会在窗户关闭之前挂起相当长的一段时间(沙滩球继续旋转......)。CoreData应用程序需要太长时间才能退出
如何使窗口立即消失,之前 MOC的保存? 我试图在AppDelegate
中插入window.close()
,applicationShouldTerminate
,但它没有效果。
我的代码删除没有什么特别的,除了层次真的很大。类似于
let items = self.items as! Set<Item>
Group.removeItems(items)
for i in items {
self.managedObjectContext?.deleteObject(i)
}
Item
是一个层级实体。 Group
与项目有一对多的关系。 removeItems
由CoreData与@NSManaged
生成。
非常感谢。
更新
我尝试下面的代码,保存仍块的UI。
@IBAction func quit(sender: AnyObject) {
NSRunningApplication.currentApplication().hide()
NSApp.terminate(sender)
}
func applicationShouldTerminate(sender: NSApplication) -> NSApplicationTerminateReply
{
let op = NSBlockOperation {() -> Void in
do {
try self.managedObjectContext.save()
} catch {
print("error")
}
NSOperationQueue.mainQueue().addOperationWithBlock({() -> Void in
NSApp.replyToApplicationShouldTerminate(true)
})
}
op.start()
return .TerminateLater
}
当创建/删除的管理对象数量很大时,这并不会使窗口关闭。
然后,我改为以下,由@bteapot建议。仍然没有效果。该窗口仍然不会立即关闭。
@IBAction func quit(sender: AnyObject) {
NSRunningApplication.currentApplication().hide()
NSApp.terminate(sender)
}
func applicationShouldTerminate(sender: NSApplication) -> NSApplicationTerminateReply {
let op = NSBlockOperation {() -> Void in
self.managedObjectContext.performBlock({() -> Void in
do {
try self.managedObjectContext.save()
} catch {
print("errr")
}
})
NSOperationQueue.mainQueue().addOperationWithBlock({() -> Void in
NSApp.replyToApplicationShouldTerminate(true)
})
}
dispatch_async (dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
{() -> Void in
op.start()
})
return .TerminateLater
}
最后我有点解决了这个问题,虽然UI仍然受阻有时,即使使用相同的测试数据。
使用可以在这里找到的方法:https://blog.codecentric.de/en/2014/11/concurrency-coredata/,Core Data background context best practice,https://www.cocoanetics.com/2012/07/multi-context-coredata/
首先,我做了一个backgroundMOC
与.PrivateQueueConcurrencyType
lazy var backgroundMOC : NSManagedObjectContext = {
let coordinator = self.persistentStoreCoordinator
let moc = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType)
moc.persistentStoreCoordinator = coordinator
moc.undoManager = nil
return moc
}()
然后使它原来商务部Prent公司。
lazy var managedObjectContext: NSManagedObjectContext = {
var managedObjectContext = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)
// managedObjectContext.persistentStoreCoordinator = coordinator
managedObjectContext.parentContext = self.backgroundMOC
managedObjectContext.undoManager = nil
return managedObjectContext
}()
两种保存方法。
func saveBackgroundMOC() {
self.backgroundMOC.performBlock {() -> Void in
do {
try self.backgroundMOC.save()
NSApp.replyToApplicationShouldTerminate(true)
} catch {
print("save error: bg")
}
}
}
func saveMainMOC() {
self.managedObjectContext.performBlock {() -> Void in
do {
try self.managedObjectContext.save()
self.saveBackgroundMOC()
} catch {
print("save error")
}
}
}
更改applicationShouldTerminate()
到
func applicationShouldTerminate(sender: NSApplication) -> NSApplicationTerminateReply {
if !managedObjectContext.commitEditing() {
NSLog("\(NSStringFromClass(self.dynamicType)) unable to commit editing to terminate")
return .TerminateCancel
}
if !managedObjectContext.hasChanges {
return .TerminateNow
}
saveMainMOC()
return .TerminateLater
}
它是如此缓慢的原因是我使用NSXMLStoreType
代替NSSQLiteStoreType
。
调用'[[NSRunningApplication currentApplication] hide];',从'applicationShouldTerminate'返回'NSTerminateLater'并让应用程序完成它应该完成的任务。然后调用'replyToApplicationShouldTerminate:YES' – bteapot
因此,我应该在CoreApp MOC中保存并在'applicationShouldTerminate:'启动的'NSOperation'中调用'replyToApplicationShouldTerminate:YES',然后返回NSTerminateLater? – LShi
否,序列为:1) 。用户命令应用程序退出。 2)。应用程序委托收到'applicationShouldTerminate:'调用。 3)。在这种方法中你必须a)。 b)在后台线程中启动保存进程。返回'NSTerminateLater'。 4)。当保存过程完成后,您应该在主线程上调用'replyToApplicationShouldTerminate:YES'。 – bteapot