Core Data 管理对象上下文设计建议

2024-02-13

我们正在开发一个企业级应用程序,它将使用核心数据存储数以万计的对象,但我们在多个方面都遇到了问题。


我们的应用程序有几个独立的系统,可以在需要时对数据进行操作。这些系统包括项目的发现、项目的加载、同步和UI显示。如果我们正确地设计我们的软件,那么由于不同的系统修改相同的对象而导致的合并冲突应该很少甚至没有。每个系统都有自己的操作队列,全部在后台执行。我们希望将所有对象创建和修改保留在后台,以最大程度地减少 UI 性能问题,尤其是在初始启动期间,可能会根据服务器上的数据创建数千个对象。在这里,我们的各种设计尝试遇到了一些问题。在这些启动过程中会消耗大量内存,并且所有上下文和子上下文的编排不正确,从而导致死锁和崩溃。 我们尝试了以下设计:

  • 一根NSPrivateQueueConcurrencyType有一个子对象的托管对象上下文NSMainQueueConcurrencyType语境。 UI 获取结果控制器使用此子上下文来获取结果。来自NSMainQueueConcurrencyType子上下文,我们创建了一个NSPrivateQueueConcurrencyType子上下文,我们称之为“ savingContext”,每个后台操作都会创建该“ savingContext”的子上下文,进行更改,最后执行我们所谓的“深度保存”,递归地保存到顶部。我们最初选择这种设计是为了不必处理NSManagedObjectContextDidSaveNotification来自许多不同子上下文的通知。我们结束了对NSPrivateQueueConcurrencyType上下文和对对象的访问performBlockAndWait:。从功能上来说,这个设计是有效的。所有更改和插入都保存到持久存储中,并且 UI 随更改而更新。这引入了两个问题。其中之一是在启动过程中用户界面滞后,因为合并的更改经过NSMainQueueConcurrencyType子上下文,更重要的是,在启动期间内存使用率非常高。由于无法调用,我们会遇到过高的 RAM 使用量reset在上下文中递归(因为主 UI 子上下文也在那里)和/或缺乏何时调用的知识refreshObject:mergeChanges:。于是我们走了一条不同的路。
  • 有两个与持久存储协调器链接的顶级上下文,一个NSPrivateQueueConcurrencyType用于保存子上下文,以及NSMainQueueConcurrencyType用于UI显示。这NSMainQueueConcurrencyTypeNSManagedObjectContextDidSaveNotification来自主站的通知NSPrivateQueueConcurrencyTypecontext 并将它们合并到主线程中。每个后台操作都会创建一个主上下文的子上下文NSPrivateQueueConcurrencyTypecontext,也具有私有队列并发类型,执行它的操作,递归地执行“深度保存”,即对当前上下文执行保存,对其父级执行深度保存的递归调用,对当前上下文调用重置并再次保存。这样我们就可以避免内存问题,因为创建的对象在保存后会快速释放。然而,通过这种设计,我们遇到了很多问题,例如死锁、NSInternalInconsistencyException异常和获取的结果控制器不更新 UI,尽管有保存通知NSMainQueueConcurrencyType语境。这也会导致 UI 中的初始加载时间显着减慢。在之前的设计中,获取结果控制器返回结果的速度非常快,而这会导致 UI 阻塞几秒钟,直到视图加载(我们在中初始化获取结果控制器)viewDidLoad).

我们尝试了许多中间设计,但它们都围绕着相同的问题,要么非常高的内存使用率,获取的结果控制器不更新 UI 或死锁,NSInternalInconsistencyException例外情况。


我真的很沮丧。我忍不住觉得我们的设计对于一些本应相当简单的东西来说过于复杂,而正是我们缺乏对一些基本原理的理解才导致了我们的死亡。


那么你们有什么建议呢?对于我们的环境,您会推荐什么安排?我们应该如何管理不同线程中的不同上下文?释放插入对象和重置上下文的最佳实践?避免死锁?此时,我们将不胜感激所有帮助。


我还看到了 MagicalRecords 类别的推荐。推荐吗?我们已经投资使用核心数据类型,那么使用 MR 进行迁移有多困难?


首先,为了管理内存,第二种架构为您提供了更大的灵活性。

其次,有两种内存需要管理:malloc 内存和常驻 VM 内存。您可以拥有较低的 malloc 内存占用量,但仍然拥有较大的 VM 驻留区域。根据我的经验,这是由于 Core Data 积极保留新插入的项目。我通过保存后修剪通知解决了这个问题。

第三,MOC 价格便宜。使用它们并扔掉它们。换句话说,尽早且经常释放内存。

第四,尝试在主 MOC 上几乎不做任何数据库方面的事情。是的,这听起来适得其反。我的意思是,所有复杂的查询实际上都应该在后台线程上完成,然后将结果传递到主线程,或者在利用现在填充的行缓存的同时从主线程重做查询。通过这样做,您可以保持 UI 的活力。

第五,在我的多队列应用程序中,我尝试让所有保存真正发生在后台。这使我的主要 MOC 保持快速并与来自网络的数据保持一致。

第六,NSFetchedResultsController 是一个非常有用但专门的控制器。如果您的应用程序将其推到其权限范围之外,它就会开始锁定您的界面。当发生这种情况时,我会通过自己监听 -didSave 通知来滚动自己的控制器。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Core Data 管理对象上下文设计建议 的相关文章

  • Xcode 8 / Swift 3:“UIViewController 类型的表达式?未使用”警告

    我有以下函数 它之前编译得很干净 但在 Xcode 8 中生成警告 func exitViewController navigationController popViewController animated true UIViewCon
  • 将 UIToolBar 添加到所有键盘(swift)

    我正在尝试以尽可能少的重复次数将自定义 UIToolBar 添加到我的所有键盘中 我目前的做法要求我将代码添加到所有 viewDidLoads 中 并将每个文本字段的委托分配给我正在使用的 viewController 我尝试创建自己的 U
  • 如何检测用户是否第一次打开应用程序[重复]

    这个问题在这里已经有答案了 是否可以检测用户是否是第一次打开iOS应用程序 使用Objective C 我想在用户第一次打开应用程序时显示欢迎消息 但之后不再向他们显示 我正在寻找类似的东西 BOOL firstTime AppDelega
  • 使用来自多个 kafka 主题的消息的最佳实践是什么?

    我需要消费来自不同卡夫卡主题的消息 我是否应该为每个主题创建不同的消费者实例 然后根据分区数量启动一个新的处理线程 或者 我应该从单个消费者实例订阅所有主题 并且应该启动不同的处理线程 感谢和问候 梅加 唯一的规则是 您必须考虑 Kafka
  • Interlocked.CompareExchange 的返回值是否有一些充分的理由

    The Interlocked CompareExchange 方法 docs https learn microsoft com en us dotnet api system threading interlocked comparee
  • 如何使用 CNContacts 快速获取手机号码?

    我有一些代码可以检索用户联系人中的所有电话号码 但只想过滤掉手机号码 目前 我只是通过将第一个数字为 或第二个数字为 7 的数字添加到数组中来实现此目的 如下所示 func findContacts gt CNContact let key
  • 如何为 iPhone 6+、6 和 5 指定不同尺寸?

    我想让 iPhone 6 6 和 5 上的视图看起来几乎相同 在附图中 我的意思是 例如 取消 按钮在 iPhone 5 中距离屏幕左边缘应为 30 像素 在 6 中为 35 像素 在 6 中为 45 像素 其他元素也类似 如何为每种类型设
  • 在 iOS 7 中 viewForHeaderInSection 部分是从 1 开始而不是从 0 开始

    我正在处理UITableView在我的项目中 这个项目是在 Xcode 4 5 中创建的 现在我正在使用 Xcode 5 所以我的问题是何时在 iOS 6 中运行我的项目 viewForHeaderInSection方法部分从 0 开始没问
  • 使用数组中的字符串淡入/淡出标签

    func setOverlayTitle self overlayLogo text Welcome var hello String Bon Jour GUTEN nMORGEN BONJOUR HOLA BUENOS D AS BUON
  • Spring Batch 多线程 - 如何使每个线程读取唯一的记录?

    这个问题在很多论坛上都被问过很多次了 但我没有看到适合我的答案 我正在尝试在我的 Spring Batch 实现中实现多线程步骤 有一个包含 100k 条记录的临时表 想要在 10 个线程中处理它 每个线程的提交间隔为 300 因此在任何时
  • 在 WKWebView 中禁用缩放?

    有谁知道在 WKWebView 中禁用双击和捏缩放的简单方法 我尝试过的任何方法都不起作用 Webview scrollView allowsMagnification false Error value of type WKWebView
  • 未知异常和崩溃

    当我尝试快速滚动表格视图或从远程重新加载数据时 我的应用程序崩溃了 当我先进行远程获取然后滚动表格视图时 一切似乎都工作正常 我不知道下面的崩溃日志意味着什么 它只是有时工作正常 有时崩溃 Incident Identifier 710A1
  • 在 iOS 上使用 RNCryptor 异步解密大文件

    我需要在 iOS 上使用 RNCryptor 异步解密一个大文件 以便显示进度条 我在任何地方都找不到示例 因此尝试了我猜对的方法 但是 我想出的方法不起作用 解密器的处理程序从未被调用 并且线程在发送所有数据后因 EXC BAD ADDR
  • 当应用程序进入前台时,如何重新启动基于块的动画?

    我有以下基于块的动画 UIView animateWithDuration 0 5f delay 0 0f options UIViewAnimationOptionRepeat UIViewAnimationOptionAutorever
  • 临时表是线程安全的吗?

    我正在使用 SQL Server 2000 它的许多存储过程广泛使用临时表 数据库的流量很大 我担心创建和删除临时表的线程安全性 假设我有一个存储过程 它创建了一些临时表 它甚至可以将临时表连接到其他临时表等 并且还可以说两个用户同时执行存
  • 通过 Button Swift 中的标签发送行和部分

    我里面有这个cellForRowAtIndexPath cell plusBut tag indexPath row cell plusBut addTarget self action plusHit forControlEvents U
  • Xcode 异步单元测试在主线程上等待

    我正在尝试使用 Xcode 中的单元测试来测试一些异步代码 但主线程被阻塞 问题在于 某些正在测试的代码期望从 iOS 类 AVFoundation 接收回调 但是 AVFoundation 类似乎只会在主线程上回调 问题是 如果我正在进行
  • 使用日期 Swift 3 对字典数组进行排序

    我有一个名为 myArray 的数组 其中添加了字典 我希望该字典按时间排序 这是字典中的键 那个时间是在 String 中 时间的日期格式为 yyyy MM dd HH mm ss 我尝试使用下面的代码解决方案 但给出了 从 字符串转换
  • 使用强光混合模式时突出显示伪影

    我正在 iPhone 应用程序中使用顶部图像的 HardLight 混合模式混合两个图像 它看起来像这样 UIGraphicsBeginImageContext size sourceImage drawInRect rectangle b
  • 致命错误:在 Swift 中解包可选值时意外发现 nil

    所以我试图获取 Swift 中输入字段的文本 这就是我得到的 class ViewController UIViewController IBOutlet var passwordField UITextField IBOutlet var

随机推荐