随着时间的流逝,NSManagedObject积累有问题

Cod*_*key 3 core-data ios

我有一个应用程序,可以从TCP / IP端点连续接收XML消息流。收到每条消息后,应用程序将其内容摘要到一组核心数据实体中。这是通过三个上下文结构完成的:

  • 主(私人队列)
  • 主(主队列->主)
  • 流(专用队列->主)

这种安排使流处理脱离主线程。该应用程序通常每秒或每两秒钟接收10-150条消息。解构并保留每个消息之后,将保存Stream上下文。在A6级设备上,CPU使用率通常不足15%。

但是我的问题是记忆。如果我将NSFetchedResultsController连接到Main上下文,则它们到达时会得到很好的消息流。但是,如果进行概要分析,我会发现我的NSManagedObject计数逐渐增加。最终,内存压力将导致应用终止。

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

Instruments指出所有对象仍处于活动状态。在互连网上浏览时,我相信我可能会有一个保留周期,从而不会导致对象出现故障。但是,在文档中尚不清楚使用“ refreshObject”的建议是否适用于此。

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

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

任何想法将不胜感激。

eof*_*ter 5

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

在当前配置中,Stream上下文填充对其父级施加了额外的压力。而且,如果Stream环境中发生了重大更新,则这种压力将变得更加明显。

首先,当Stream上下文需要执行需要锁定的操作时,它将锁定两个父对象。

其次,当在Stream上下文中发生保存时,所有更改都推回到父级Main上下文中。而且您无法控制它。如果Main上下文中有一个获取的结果控制器,则保存后它将一一重播所有更改。而且如果更新很大,将带来很大的开销。绝对在CPU中,可能在内存中。

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

这种模式效率更高,但是会增加复杂性。您需要考虑如何在其他上下文中刷新数据。您需要注意这一点,因为Core Data不会接触完全实现的对象。(setShouldRefreshRefetchedObjects由于苹果确认的错误,设置也无济于事。)

例如,您在Main上下文中获取了一些对象,访问了其属性以将其显示在屏幕上。该对象不再是故障。然后,您的Stream上下文(现在直接使用持久性存储协调器进行配置)更新了相同的属性。即使您在Main上下文中进行重新提取并且对象将出现在搜索结果中,对象属性也不会被更新。

因此,您可以使用如下所示的内容:

- (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];
            }
        }
    }];
}
Run Code Online (Sandbox Code Playgroud)

这将刷新主环境和主环境中的更新对象。

当Stream上下文中的保存空间不是很大时,您可以使用标准的merge方法将更改合并到其他两个上下文中。使用提取的结果控制器时,您将能够在删除和插入对象时看到漂亮的单元动画。受影响的对象的数量救你可以从NSInsertedObjectsKeyNSUpdatedObjectsKeyNSDeletedObjectsKey在用户信息的键上下文做保存通知。

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