2015-12-23 103 views
1

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

+1

調用'[[NSRunningApplication currentApplication] hide];',從'applicationShouldTerminate'返回'NSTerminateLater'並讓應用程序完成它應該完成的任務。然後調用'replyToApplicationShouldTerminate:YES' – bteapot

+0

因此,我應該在CoreApp MOC中保存並在'applicationShouldTerminate:'啓動的'NSOperation'中調用'replyToApplicationShouldTerminate:YES',然後返回NSTerminateLater? – LShi

+0

否,序列爲:1) 。用戶命令應用程序退出。 2)。應用程序委託收到'applicationShouldTerminate:'調用。 3)。在這種方法中你必須a)。 b)在後臺線程中啓動保存進程。返回'NSTerminateLater'。 4)。當保存過程完成後,您應該在主線程上調用'replyToApplicationShouldTerminate:YES'。 – bteapot

回答

0

退出應用程序可能需要一段時間,因爲它將首先清空隊列中的進程。 您是否要立即放棄捨棄父母或孩子MOC中的所有內容?但是這會導致數據丟失。

如果您有多窗口應用程序,那麼只關閉窗口但不能退出應用程序。

如果您正確地管理了它,成千上萬的條目不應超過5秒才能得到處理和保存。您的代碼中可能存在一些漏洞,請嘗試優化使用Instruments,CoreData分析器工具,以幫助您瞭解它耗盡的時間。

要隱藏窗口,您可以使用下面的窗口,在後臺進行所有的coredata處理,一旦完成所有操作,應用程序將終止。

[self.window orderOut:nil]; 
+0

不應丟棄數據更改。即使我在'moc.save()'之前添加'windows.close()',窗口仍然會在那裏,直到保存結束。 – LShi

+0

如果您可以顯示代碼的寫法和保存方式,那就太好了。也可以嘗試'CoreData Profiler'。 –

+0

我使用Xcode生成'applicationShouldTerminate:'在'AppDelegate'中進行保存。我認爲所花費的時間是合理的。我想立即隱藏窗口,感覺很快。 – LShi

相關問題