首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >问题NSManagedObject积累随时间的推移

问题NSManagedObject积累随时间的推移
EN

Stack Overflow用户
提问于 2014-01-27 03:34:01
回答 1查看 772关注 0票数 4

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

  • 主机(专用队列)
  • 主(主队列->主)
  • 流(私有队列-> Main)

这种安排使流处理远离主线程。应用程序通常每秒钟接收10-150条消息。流上下文的保存是在每条消息被解构和持久化之后进行的。在A6级别的设备上,CPU使用率通常不足15%。

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

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

仪器注意到所有的物体都是活的。在互联网上徘徊,让我相信我可能会有一个保留周期,导致对象不会出错。然而,使用"refreshObject“的建议在文档中并不明确,它将在这里应用。

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

其中一个想法是在保存完每几百条消息后重置Stream上下文。如果我断开FRC,我可以保持基本水平-但这感觉不对,并没有解决问题时,我连接FRC备份。

任何想法都将不胜感激。

EN

回答 1

Stack Overflow用户

发布于 2014-01-27 10:34:40

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

在当前的配置中,Stream给它的父母增加了额外的压力。如果大更新发生在Stream上下文中,这种压力就会变得更加明显。

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

其次,当保存发生在Stream上下文中时,所有更改都被推回父上下文,即主上下文。而你却无法控制它。如果主上下文中有一个获取的结果控制器,那么在保存时,它将一个一个地重播所有的更改。如果更新很大,就会带来很大的开销。肯定是在CPU里,可能在内存里。

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

这种模式效率更高,但也带来了复杂性成本。您需要考虑如何在其他上下文中刷新数据。您需要处理这个问题,因为Core数据没有接触到完全实现的对象。(设置setShouldRefreshRefetchedObjects也无济于事,因为苹果向我证实了这个错误。)

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

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

代码语言:javascript
复制
- (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];
            }
        }
    }];
}

这将刷新主上下文和主上下文中更新的对象。

当Stream上下文中的保存不是很大时,您可以使用标准的合并方法将更改合并到其他两个上下文中。当使用获取结果控制器时,您将能够看到有关对象删除和插入的良好的单元格动画。您可以从上下文中用户信息的NSInsertedObjectsKeyNSUpdatedObjectsKeyNSDeletedObjectsKey键中获得的受保存影响的对象数量--did-保存通知。

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

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/21372607

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档