gpt4 book ai didi

ios - 随着时间的推移,有问题的 NSManagedObject 积累

转载 作者:塔克拉玛干 更新时间:2023-11-01 21:22:18 25 4
gpt4 key购买 nike

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

  • 大师(私有(private)队列)
  • Main(主队列 -> Master)
  • 流(专用队列 -> 主队列)

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

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

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

仪器注意到所有对象仍然存在。在互联网上闲逛让我相信我可能有一个保留周期导致对象没有错误。但是,使用“refreshObject”的建议在此处适用的文档中并不清楚。

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

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

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

最佳答案

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

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

首先,当 Stream 上下文需要做一些需要锁定的事情时,它会锁定两个父级。

其次,当在 Stream 上下文中发生保存时,所有更改都会被推回父级,即 Main 上下文。你无法控制它。如果 Main 上下文中有一个 fetched results controller,那么在保存时它将逐个重放所有更改。而且如果更新量很大,会带来很大的开销。肯定在 CPU 中,也可能在内存中。

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

此模式效率更高,但会带来复杂性成本。您需要考虑如何在其他上下文中刷新数据。你需要注意这一点,因为 Core Data 不接触完全实现的对象。 (设置 setShouldRefreshRefetchedObjects 也无济于事,因为 Apple 向我确认了这个错误。)

例如,您在 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];
}
}
}];
}

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

当 Stream 上下文中的保存量不大时,您可以使用标准合并方法简单地将更改合并到其他两个上下文中。当使用 fetched results controller 时,你将能够在对象删除和插入时看到漂亮的单元格动画。您可以从 context-did- 中用户信息的 NSInsertedObjectsKeyNSUpdatedObjectsKeyNSDeletedObjectsKey 键获取保存中受影响的对象数保存通知。

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

关于ios - 随着时间的推移,有问题的 NSManagedObject 积累,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21372607/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com