我的應用程序在運行時可能會創建/刪除數千個託管對象。我使用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