同时可靠地使用核心数据

Joh*_*ley 7 iphone cocoa-touch core-data nsmanagedobjectcontext ios

我正在构建我的第一个iOS应用程序,理论上应该非常简单,但我很难让它足够防弹,让我有信心将它提交到App Store.

简而言之,主屏幕具有表格视图,在选择行时,它将分段到另一个表格视图,该表格视图以主 - 细节方式显示与所选行相关的信息.基础数据每天从Web服务检索为JSON数据,然后缓存在Core Data存储中.删除当天之前的数据以阻止SQLite数据库文件无限增长.所有数据持久性操作都使用Core Data执行,并具有NSFetchedResultsController详细信息表视图的基础.

我看到的问题是,如果你在主屏幕和细节屏幕之间快速切换几次,同时检索,解析和保存新数据,应用程序会冻结或完全崩溃.似乎存在某种竞争条件,可能是由于Core Data在后台导入数据而主线程正在尝试执行获取,但我猜测.我在捕获任何有意义的崩溃信息时遇到了麻烦,通常它是Core Data堆栈中的一个SIGSEGV.

下表显示加载详细信息表视图控制器时发生的事件的实际顺序:

Main Thread                          Background Thread
viewDidLoad

                                     Get JSON data (using AFNetworking)

Create child NSManagedObjectContext (MOC)

                                     Parse JSON data
                                     Insert managed objects in child MOC
                                     Save child MOC
                                     Post import completion notification

Receive import completion notification
Save parent MOC
Perform fetch and reload table view

                                     Delete old managed objects in child MOC
                                     Save child MOC
                                     Post deletion completion notification

Receive deletion completion notification
Save parent MOC

在JSON数据到达时触发AFNetworking完成块后,将NSManagedObjectContext创建嵌套并传递给"导入器"对象,该对象解析JSON数据并将对象保存到Core Data存储.导入器使用performBlockiOS 5中引入的新方法执行:

NSManagedObjectContext *child = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    [child setParentContext:self.managedObjectContext];        
    [child performBlock:^{
        // Create importer instance, passing it the child MOC...
    }];
Run Code Online (Sandbox Code Playgroud)

导入器对象观察其自己的MOC NSManagedObjectContextDidSaveNotification,然后发布自己的通知,该通知由详细信息表视图控制器观察.发布此通知时,表视图控制器会在其自己的(父)MOC上执行保存.

我使用与"删除"对象相同的基本模式,在导入当天的新数据后删除旧数据.在获取的结果控制器提取新数据并重新加载详细信息表视图之后,这会异步发生.

我没做的一件事是观察任何合并通知或锁定任何托管对象上下文或持久性存储协调器.这是我应该做的事吗?我有点不确定如何正确地构建这一切,所以将不胜感激任何建议.

Chr*_*hey 2

只是一个架构想法:

根据您所说的数据刷新模式(每天一次,删除和添加数据的完整周期),我实际上会每天创建一个新的持久存储(即以日历日期命名),然后在完成通知中,表视图设置一个与新商店(可能还有新的 MOC)关联的新 fetchedresultscontroller,并使用它进行刷新。然后应用程序可以(在其他地方,也许也由该通知触发)完全销毁“旧”数据存储。这种技术将更新处理与应用程序当前使用的数据存储分离,并且“切换”到新数据可能被认为更加原子化,因为发生的更改只是开始指向新数据而不是希望您在写入新数据(但尚未完成)时,无法捕获处于不一致状态的存储。

显然,我遗漏了一些细节,但我倾向于认为,在使用时更改的大量数据应该重新架构,以减少您遇到的那种崩溃的可能性。

很高兴进一步讨论...