我正在构建我的第一个 iOS 应用程序,理论上它应该非常简单,但我很难让它足够安全,让我有信心将其提交到 App Store。
简而言之,主屏幕有一个表视图,在选择一行后,它会转到另一个表视图,该表视图以主从方式显示与所选行相关的信息。底层数据每天从 Web 服务中以 JSON 数据形式检索一次,然后缓存在核心数据存储中。当天之前的数据将被删除,以阻止 SQLite 数据库文件无限增长。所有数据持久化操作均使用 Core Data 执行,NSFetchedResultsController
支持详细信息表视图。
我看到的问题是,如果在检索、解析和保存新数据的同时在主屏幕和详细屏幕之间快速切换几次,应用程序将完全冻结或崩溃。似乎存在某种竞争条件,可能是由于核心数据在后台导入数据而主线程尝试执行获取,但我猜测。我很难捕获任何有意义的崩溃信息,通常是核心数据堆栈深处的 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 数据并将对象保存到核心数据存储中。导入器使用新的执行performBlock
iOS 5中引入的方法:
NSManagedObjectContext *child = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[child setParentContext:self.managedObjectContext];
[child performBlock:^{
// Create importer instance, passing it the child MOC...
}];
导入器对象观察它自己的 MOCNSManagedObjectContextDidSaveNotification
然后发布自己的通知,该通知由详细表视图控制器观察到。当发布此通知时,表视图控制器在其自己的(父)MOC 上执行保存。
我使用与“删除器”对象相同的基本模式来在导入当天的新数据后删除旧数据。在获取结果控制器获取新数据并且重新加载详细信息表视图之后,这会异步发生。
我没有做的一件事是观察任何合并通知或锁定任何托管对象上下文或持久存储协调器。这是我应该做的事情吗?我有点不确定如何正确地构建这一切,因此将不胜感激任何建议。