处理父子 managedObjectContexts 的应用程序崩溃
Posted
技术标签:
【中文标题】处理父子 managedObjectContexts 的应用程序崩溃【英文标题】:Handling app crashes for Parent-Child managedObjectContexts 【发布时间】:2015-09-15 05:14:34 【问题描述】:这是我创建的示例应用程序应用程序,用于模拟我正在处理的案例。它是一个使用 CoreData 和 Swift 2.0 和 Xcode 7 beta4 的单视图应用程序
因此,在我的视图控制器中,我创建了一个 privateObjectContext
,它是 mainManagedObjectContext
的子级
let mainMOC = AppDelegate().managedObjectContext
var privateObjectContext : NSManagedObjectContext?
override func viewDidLoad()
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
privateObjectContext = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType)
privateObjectContext?.parentContext = mainMOC
我知道在子 MOC 中保存会将其同步到父级,然后保存父级会将其保存到持久存储中,但是每次我保存子 MOC 时都保存主 MOC 没有意义,并且使子 MOC 的目的MOC 冗余。所以在我完成所有测试后,我保存了我的父 MOC,它确实按预期存储在持久存储中。
但是当我模拟应用程序崩溃时(通过转到任务管理器并强制终止应用程序)它不会存储在持久管理器中;因此它应该有这个
func applicationWillTerminate(application: UIApplication)
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
// Saves changes in the application's managed object context before the application terminates.
self.saveContext()
func saveContext ()
if managedObjectContext.hasChanges
do
try managedObjectContext.save()
catch
// Replace this implementation with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
let nserror = error as NSError
NSLog("Unresolved error \(nserror), \(nserror.userInfo)")
abort()
但是 managedObjectContext.hasChanges
返回 false,尽管它在 ViewController 中发生了变化
我在 MOC 生命周期的某个地方错了吗?
--编辑 我使用 NSManagedObjectContext 的扩展来批量创建测试对象
privateObjectContext?.performBlock
self.privateObjectContext?.createTestObjects(100)
(person: Person, index) in
person.name = "Test Person \(index)"
do
try self.privateObjectContext?.save()
catch
print(error)
在此之后,如果我从我的主 MOC 获取,那么我会得到预期的 100 条记录。
print(mainMOC.hasChanges) //true
let persons = mainMOC.fetchAll(Person)
print(persons.count) //100
但是在应用程序强行崩溃后,主 MOC 仍然没有任何变化。
【问题讨论】:
在您的案例中使用子上下文的动机是什么?您是否看到任何并发使用情况? 我有很多数据需要在我的主应用程序中定期保存在后台。因此,正在考虑通过子 MOC 将其异步保存到 MOC 的选项,然后当用户完成将其存储在持久存储中的任务时。当应用程序在任务之间崩溃时,我必须处理这种情况,因此问题 理想情况下,如果您打算立即将更新写回磁盘,则在父上下文中的保存应紧跟在子上下文中的保存之后。 我实际上并不想立即将更改写入磁盘并占用我的主队列,但前提是应用程序崩溃或其他情况 【参考方案1】:应用程序将终止的方法基本上是从不使用的,所以你不应该依赖它。您也不应该真正编写代码以节省崩溃,首先您的应用程序不应该崩溃,其次很难知道崩溃时哪些数据无效,因此您可能会破坏其他良好的数据。
一般来说,您应该立即保存或批量保存到永久存储。
请注意,您还可以以不同的方式构建托管对象上下文,以便处理和保存事物,然后将其合并到主上下文中。如果您在保存时确实在 UI 上看到问题,您可能只想进行这项工作。
严格来说,问题在于您没有保存子 MOC(至少在我们可以看到的代码中没有)。因此,当您保存主 MOC 时,它还没有任何子级更改,也没有什么要保存的。
【讨论】:
我考虑的情况是应用程序由于某种原因崩溃的最坏情况。我肯定会不时将数据保存到持久协调器。但是当我杀死它时会调用applicationWillTerminate
方法,但 MOC 没有显示任何变化。这是为什么呢?
嗨..我已经编辑了我的代码以显示我保存我的子 MOC 的测试用例,它确实反映在主 MOC 中,但它没有显示 ApllicationWillTerminate 方法中的更改。 NSManagedObjectContext 是一个类,所以应该正确引用,或者我可能在它的生命周期中遗漏了一些东西【参考方案2】:
如果您要进行大量保存,并且正如@Wain 正确指出的那样,在终止时执行保存不是一个好主意,那么有一种更推荐的方法可以在不阻塞主线程的情况下执行此操作。您将需要创建一个根上下文,它与存储协调器关联并在非主队列中运行。您的主要上下文可以是此上下文的子上下文。
请参阅
中的“异步保存”部分https://www.cocoanetics.com/2012/07/multi-context-coredata/
【讨论】:
我可以调查一下。谢谢!!虽然我仍然不明白为什么即使在保存了我的孩子 MOC 之后主 MOC 也没有变化 好的,有没有可能看看你的实际代码?以上是关于处理父子 managedObjectContexts 的应用程序崩溃的主要内容,如果未能解决你的问题,请参考以下文章
NSManagedObject 总是在同一个 ManagedObjectContext 上创建
尝试从 iOS 中的 Singleton 类初始化 ManagedObjectContext
self.managedObjectContext 和 managedObjectInstance.managedObjectContext 有啥区别?