Ios 有问题的NSManagedObject随时间累积

Ios 有问题的NSManagedObject随时间累积,ios,core-data,Ios,Core Data,我有一个应用程序,它不断地从TCP/IP端点接收XML消息流。收到每条消息后,应用程序将其内容分解为一组核心数据实体。这是通过三个上下文结构实现的: 主队列(专用队列) 主队列(主队列->主队列) 流(专用队列->主队列) 这种安排使流处理远离主线程。该应用程序通常每秒或每秒接收10-150条消息。流上下文的保存发生在每条消息解构和持久化之后。A6级设备的CPU使用率通常低于15% 然而,我的问题是记忆力。若我将一个NSFetchedResultsController连接到主上下文,我会在消

我有一个应用程序,它不断地从TCP/IP端点接收XML消息流。收到每条消息后,应用程序将其内容分解为一组核心数据实体。这是通过三个上下文结构实现的:

  • 主队列(专用队列)
  • 主队列(主队列->主队列)
  • 流(专用队列->主队列)
这种安排使流处理远离主线程。该应用程序通常每秒或每秒接收10-150条消息。流上下文的保存发生在每条消息解构和持久化之后。A6级设备的CPU使用率通常低于15%

然而,我的问题是记忆力。若我将一个NSFetchedResultsController连接到主上下文,我会在消息到达时获得一个良好的消息流。但是,如果我进行概要分析,我会注意到我的NSManagedObject计数逐渐增加。最终,内存压力将导致应用程序终止

经过12分钟的评测,该应用程序已经消耗了6300条XML消息,并解析了121000个属性。属性消耗7.8MB,消息消耗438KB,应用程序总大小现在为54MB。显然,这是不可持续的

仪器注意到所有的物体仍然是活的。在互联网络上四处游荡使我相信我可能有一个保留周期,从而使对象不会出现故障。然而,使用“refreshObject”的建议在文档中并不清楚是否适用于这里

一旦收到XML,就会创建一个消息实体。接下来,使用XML的根节点作为其名称和相关位创建一个类型实体。类似地,为这些元素的每个元素和子元素以及XML的任何内联属性创建一个属性元素。这是一个有趣的部分,因为它有一个对消息的引用(用于所有属性的平面表示)以及与自身的分层childProperties关系。在该过程结束时,将保存上下文,主上下文将拾取该上下文,FRC将显示新行

一种想法是,每隔几百条消息保存一次,就重置流上下文。如果我断开FRC,我基本上可以保持水平-但是这感觉是错误的,当我将FRC重新连接时,并不能解决问题


如果您有任何想法,我们将不胜感激。

我建议您使用与主上下文相同的持久存储协调器配置流上下文。并且可能会定期重置流上下文

在当前配置流上下文中,fill会对其父级施加额外的压力。如果在流上下文中发生重大更新,这种压力就会变得更加明显

首先,当流上下文需要执行某些需要锁定的操作时,它将锁定双亲

第二,当在流上下文中进行保存时,所有更改都被推回到父上下文,即主上下文。而你无法控制它。如果主上下文中有一个获取的结果控制器,则在保存时,它将逐个重播所有更改。如果更新量很大,则会带来很大的开销。肯定在CPU中,可能在内存中

我认为在后台处理大更新和刷新UI(特别是使用fetched results controller)的最佳模式是配置直接使用持久存储协调器进行大更新的上下文。然后,当发生重大更新时,只需在UI上下文中重新蚀刻即可。并且不要忘记将fetch请求上的fetch批处理大小设置为对您的案例值有意义的大小。您可以从屏幕上可见的单元格数量开始

这种模式效率更高,但会带来复杂性和成本。您需要考虑如何在其他上下文中刷新数据。您需要注意这一点,因为核心数据不会触及完全实现的对象。(设置
setShouldRefreshRefetchedObjects
也没有帮助,因为Apple向我确认了这个bug。)

例如,您在主上下文中获取某个对象,访问其属性以在屏幕上显示它。这个物体不再是一个缺陷了。然后,流上下文(现在直接配置了持久存储协调器)更新了相同的属性。即使在主上下文中重新蚀刻,并且对象将出现在搜索结果中,对象属性也不会更新

所以你可以用这样的东西:

- (void)refreshObjectsOnContextDidSaveNotification:(NSNotification *)notification {
    NSSet *updatedObjects = notification.userInfo[NSUpdatedObjectsKey];
    NSSet *updatedObjectIDs = [updatedObjects valueForKey:@"objectID"];

    [self.mainContext performBlock:^{
        for (NSManagedObject *object in [self.mainContext registeredObjects]) {
            if (![object isFault] && [updatedObjectIDs containsObject:[object objectID]]) {
                [self.mainContext refreshObject:object mergeChanges:YES];
            }
        }
    }];

    [self.masterContext performBlock:^{
        for (NSManagedObject *object in [self.masterContext registeredObjects]) {
            if (![object isFault] && [updatedObjectIDs containsObject:[object objectID]]) {
                [self.masterContext refreshObject:object mergeChanges:YES];
            }
        }
    }];
}
这将刷新主上下文和主上下文中更新的对象

当流上下文中的保存不是很大时,您可以使用标准的合并方法将更改合并到其他两个上下文中。当使用“获取结果控制器”时,您将能够在对象删除和插入时看到漂亮的单元动画。可以从上下文did save通知中的用户信息的
NSInsertedObjectsKey
nsUpdate-ObjectSkey
NSDeletedObjectsKey
键获取的保存中受影响的对象数

在每次大保存之后,您可以重置流上下文。只是不要忘记,重置后,您无法在此上下文中访问任何以前获取的对象。

您是否阅读过(包括有关插入对象的注释)?