我正在构建我的第一个iOS应用程序,从理论上讲,它应该很简单,但是我很难使其具有足够的防弹性能,使我无法自信地将其提交到App Store。

简而言之,主屏幕具有一个表格 View ,在选择一行时,它会紧靠另一个表格 View ,该表格 View 以主从方式显示与所选行相关的信息。每天一次从Web服务检索基础数据作为JSON数据,然后将其缓存在Core Data存储中。删除前一天的数据以阻止SQLite数据库文件无限期增长。所有数据持久性操作都是使用Core Data执行的,并在详细信息表 View 的基础上添加了NSFetchedResultsController

我看到的问题是,如果在检索,解析和保存新数据时几次在主屏幕和详细屏幕之间快速切换,则该应用程序将冻结或完全崩溃。似乎存在某种竞争状况,可能是由于Core Data在主线程试图执行提取时在后台导入数据,但我推测是这样。我在捕获任何有意义的崩溃信息时遇到了麻烦,通常这是位于核心数据堆栈深处的SIGSEGV。

下表显示了加载明细表 View Controller 时发生的事件的实际顺序:

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

Once the AFNetworking completion block is triggered when the JSON data has arrived, a nested NSManagedObjectContext is created and passed to an "importer" object that parses the JSON data and saves the objects to the Core Data store. The importer executes using the new performBlock method introduced in iOS 5:

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

导入器对象观察其自己的MOC的NSManagedObjectContextDidSaveNotification,然后发布其自己的通知,该通知由详细信息表 View Controller 观察到。发布此通知后,表 View Controller 将自行(父)MOC执行保存。

在导入当天的新数据之后,我将相同的基本模式与“删除程序”对象一起使用,以删除旧数据。在由获取的结果 Controller 获取了新数据并且重新加载了明细表 View 之后,这会异步发生。

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

最佳答案

在iOS 5之前,我们通常有两个NSManagedObjectContexts:一个用于主线程,一个用于后台线程。后台线程可以加载或删除数据,然后保存。然后将生成的NSManagedObjectContextDidSaveNotification传递(如您所做的那样)到主线程。我们调用mergeChangesFromManagedObjectContextDidSaveNotification:将它们带入主线程上下文。这对我们来说很好。

其中一个重要方面是,后台线程上的save:会阻塞,直到mergeChangesFromManagedObjectContextDidSaveNotification:在主线程上运行完为止(因为我们从监听器到该通知调用mergeChanges ...)。这样可以确保主线程托管对象上下文可以看到这些更改。如果您有亲子关系,我不知道是否需要这样做,但是您在旧模型中这样做是为了避免各种麻烦。

我不确定两个上下文之间具有父子关系有什么好处。从您的描述看来,最终保存到磁盘是在主线程上进行的,出于性能方面的考虑,这可能不是理想的选择。 (尤其是如果您可能要删除大量数据;在最终保存到磁盘期间,我们应用程序中删除操作的主要费用一直都在发生。)

当 Controller 出现/消失时正在运行什么代码,这可能会导致核心数据故障?您看到崩溃的是哪种堆栈跟踪?

关于iphone - 同时可靠地使用核心数据,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/11335214/

10-14 23:27
查看更多