我正在构建我的第一个 iOS 应用程序,理论上它应该非常简单,但我很难让它足够防弹,让我有信心将它提交到 App Store。
简而言之,主屏幕有一个表格视图,在选择一行后,它会连接到另一个表格视图,该表格视图以主从方式显示与所选行相关的信息。底层数据每天一次从 Web 服务中检索为 JSON 数据,然后缓存在 Core Data 存储中。删除当天之前的数据以阻止 SQLite 数据库文件无限增长。所有数据持久化操作都是使用 Core Data 执行的,并带有一个NSFetchedResultsController
基础的详细表视图。
我看到的问题是,如果您在检索、解析和保存新数据时多次在主屏幕和详细屏幕之间快速切换,应用程序将完全冻结或崩溃。似乎存在某种竞争条件,可能是由于核心数据在后台导入数据,而主线程正在尝试执行获取,但我在推测。我无法捕获任何有意义的崩溃信息,通常它是核心数据堆栈中的一个 SIGSEGV。
下表显示了加载详细信息表视图控制器时发生的事件的实际顺序:
主线程后台线程 viewDidLoad 获取 JSON 数据(使用 AFNetworking) 创建子 NSManagedObjectContext (MOC) 解析 JSON 数据 在子 MOC 中插入托管对象 拯救儿童 MOC 导入后完成通知 接收导入完成通知 保存父 MOC 执行获取和重新加载表视图 删除子 MOC 中的旧托管对象 拯救儿童 MOC 删除后完成通知 接收删除完成通知 保存父 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...
}];
导入器对象观察它自己的 MOC NSManagedObjectContextDidSaveNotification
,然后发布它自己的通知,该通知由详细表视图控制器观察。发布此通知时,表视图控制器在其自己的(父)MOC 上执行保存。
在导入当天的新数据后,我使用相同的基本模式和“删除器”对象来删除旧数据。这在获取结果控制器获取新数据并且重新加载详细信息表视图后异步发生。
我没有做的一件事是观察任何合并通知或锁定任何托管对象上下文或持久存储协调器。这是我应该做的事情吗?我有点不确定如何正确地构建这一切,所以不胜感激。