NSFetchedResultsController 提供表视图,同时同一持久存储的后台更新导致死锁

2023-12-29

仍在致力于将应用程序从每次使用或显示信息时下载信息,转变为使用 CoreData 将其缓存在手机上(由 MagicalRecord 提供)。这是在 iOS 7 上

因为我们没有设置数据推送系统来在后端的某些数据发生变化时自动更新手机的缓存数据,所以在过去的几个月里(当我们致力于应用程序的其他方面时)我一直在思考如何管理在手机上保留数据的本地副本,并能够在缓存中保留最新的数据。

我意识到,只要我仍然每次都获取数据:-(我就可以使用手机的 CoreData 支持的数据缓存来显示和使用,并且只需使用数据的获取来更新手机上的数据库。

因此,我一直在将主要数据对象从构成完整对象的下载数据转换为这些主要数据对象作为 CoreData 对象的轻型替代对象。

基本上,应用程序中的每个普通数据对象并不在内部包含该对象的所有属性,而是仅包含底层 CoreData 对象的 objectID,也可能在内部包含应用程序特定的 ID,所有其他属性都是动态的并从 CoreData 获取对象并传递(大多数属性是只读的,更新是通过批量重写 JSON 中传递的核心数据来完成的)

像这样:

- (NSString *)amount
{
    __block NSString *result = nil;

    NSManagedObjectContext *localContext = [NSManagedObjectContext MR_newContext];

    [localContext performBlockAndWait:^{
        FinTransaction  *transaction = (FinTransaction *)[localContext existingObjectWithID:[self objectID] error:nil];

        if (nil != transaction)
        {
            result = [transaction.amount stringValue];
        }
    }];

    return result;
}

有时需要设置一个,如下所示:

- (void)setStatus:(MyTransactionStatus)status
{
    [MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) {
        FinTransaction *transaction = (FinTransaction *)[localContext existingObjectWithID:[self objectID] error:nil];

        if (nil != transaction)
        {
            transaction.statusValue = status;
        }

    } completion:^(BOOL success, NSError *error){}];
}

现在,我的问题是我有一个视图控制器,它基本上使用 NSFetchedResultsController 在表视图中显示本地手机 CoreData 数据库中存储的数据。在发生这种情况的同时,用户可能开始滚动数据,手机会启动一个线程来下载数据更新,然后开始使用更新后的数据更新 CoreData 数据存储,此时它会在主线程上运行异步 GCD 回调,让获取的结果控制器重新获取其数据,并告诉表视图重新加载。

问题是,如果用户滚动初始获取结果控制器获取的数据和表视图加载,并且后台线程正在后台更新相同的 Core Data 对象,则会发生死锁。获取和重写的实体并不完全相同(当发生死锁时),即,不是读取和写入对象 ID 1,而是使用相同的持久数据存储。

每次访问(读或写)都发生在MR_saveWithBlock or MR_saveWithBlockAndWait(写入/更新数据)视情况而定,并且 [localContext PerformBlock:] 或 [localContext PerformBlockAndWait:] 可能合适。每个单独的读或写都有自己的NSManagedObjectContext。我没有看到任何地方有任何挂起的杂散挂起的更改,并且它阻塞和死锁的实际位置并不总是相同的,但总是与主线程从与后台线程所使用的相同的持久存储中读取数据有关。更新数据。

获取结果控制器的创建如下:

_frController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
                                                    managedObjectContext:[NSManagedObjectContext MR_rootSavingContext]
                                                      sectionNameKeyPath:sectionKeyPath
                                                               cacheName:nil];

然后一个performFetch已经完成了。

当我需要在表视图中显示范围数据并使用新数据在后台更新数据存储时,如何最好地构建此类操作?

当我使用时MagicalRecord对于其中的大部分内容,无论是否使用 MagicalRecord(直接 CD),我都愿意接受评论、答案等。


因此,我处理此问题的方法是查看两个托管对象上下文,每个上下文都有自己的持久存储协调器。两个持久性存储协调器都与磁盘上的同一个持久性存储进行通信。

WWDC 2013 的第 211 场会议“核心数据性能优化和调试”中详细介绍了这种方法,您可以在Apple WWDC 2013 开发者网站 https://developer.apple.com/videos/wwdc/2013/.

为了在 MagicalRecord 中使用这种方法,您需要考虑使用即将发布的 MagicalRecord 3.0 版本,其中ClassicWithBackgroundCoordinatorSQLiteMagicalRecordStack(是的,这个名字需要改进!)。它实现了 WWDC 会议中概述的方法,但您需要注意,您的项目需要进行更改才能支持 MagicalRecord 3,而且它还没有完全发布。

本质上你最终得到的是:

  • 1 x 主线程上下文:您可以使用它来填充您的 UI,以及获取的结果控制器等。永远不要在这种情况下进行更改.
  • 1 x 专用队列上下文:使用基于块的保存方法进行所有更改— 它们会自动遍历此上下文并保存到磁盘。

我希望这是有道理的——一定要观看 WWDC 会议——他们使用一些很棒的动画图来解释为什么这种方法更快(并且不应该像您现在使用的方法那样阻塞主线程)。

如果您需要的话,我很乐意提供更多详细信息。

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

NSFetchedResultsController 提供表视图,同时同一持久存储的后台更新导致死锁 的相关文章

  • 奇怪的 Facebook ID [关闭]

    Closed 这个问题需要细节或清晰度 help closed questions 目前不接受答案 我有两个 Facebook 应用程序 它们都正在开发中 其中一个是很久以前创建的 而另一个则是相当新的 自从我升级到新的 iOS Faceb
  • 剪裁为形状的 SwiftUI 图像在上下文菜单中具有透明填充

    在我的 SwiftUI 应用程序中 我的资产目录中有一张宽高比为 1 1 的图像 在我的代码中 我有一个Image使用不同的宽高比查看 将图像裁剪为新尺寸 Image My Image resizable aspectRatio conte
  • 允许用户从 UILabel 选择文本进行复制[重复]

    这个问题在这里已经有答案了 我有一个 UILabel 但如何允许用户选择其文本的一部分 我不希望用户能够编辑文本 也不希望标签 文本字段具有边框 这是不可能的UILabel 你应该使用UITextView为了那个原因 只需使用禁用编辑即可t
  • 如何创建一个仅接收一次信号,然后自行取消订阅/释放的 ReactiveCocoa 订阅者?

    我目前正在注册一个属性信号的订阅者 如下所示 RACAble self test subscribeNext id x NSLog signal fired 默认功能是每次 self test 更改时都会触发 但我只想触发一次 然后取消订阅
  • 应用因广告标识符 (IDFA) 被拒绝

    我的申请因以下原因被拒绝 您和您的应用程序 以及与您有联系的任何第三方 签订广告服务合同 可以使用广告标识符 以及通过使用广告获得的任何信息 标识符 仅用于服务广告的目的 如果一个用户 重置广告标识符 则您同意不合并 直接或间接关联 链接或
  • 将 NSDate 转换为 SWIFT 中具有特定时区的字符串

    在我的核心数据库中 我有一个带有 NSDate 属性的 新闻 实体 我的应用程序遍布全球 新闻已发布2015 09 04 22 15 54 0000法国时间 GMT 2 为了保存日期 我将其转换为 UTC 格式 let mydateForm
  • 使用 NSJSONSerialization 解析 JSON

    对此进行了太多讨论 但我不知道如何解决我的问题 这是我从 WorldWeatherOnline 获取的 JSON 数据 JSON 有效 但我不知道如何解析它 这是我的代码 后面是 JSON 请帮忙 NSError errorInfo NSD
  • 同一应用程序的不同版本取决于设备(应用程序商店)

    我已经将我的游戏提交到App Store并更新了 现在最新版本是每个下载我游戏的人都应该得到的版本 对吗 现在的问题是 当我从 iPad mini 上的 App Store 下载游戏时 我得到的是正确的版本 但是当我从 iPad 2 下载游
  • 我以前没见过的 CGRect 语法

    我在一些示例代码中看到了下面的语法 但不确定我是否理解它 CGRect imageRect CGRect size baseImage size 这只是初始化的一种简写方式吗CGRect相当于 CGRect imageRect CGRect
  • iOS 应用内购买沙箱测试显示我的密码错误

    我在 itunesconnect 中创建了一个 Sandbox Tester 帐户 并通过我在网络上注册的电子邮件验证了电子邮件地址 验证后 我尝试使用沙盒帐户在我的应用程序中购买商品 并收到更改密码的提醒 所以我做了 然后我尝试使用新密码
  • 设置使用 iPhone 相机拍摄的图像的类型

    如果我们使用 iPhone 相机拍摄照片 图像将默认以 JPEG 格式保存 我想以其他格式 例如 PNG 保存捕获的图像 是否可以 当我们从应用程序调用 iPhone 相机时 是否可以通过代码执行此操作 我们可以设置捕获图片后必须保存的图像
  • 如何自定义 NSSlider

    我正在尝试在 Cocoa 中实现一个具有 5 个值的自定义滑块 查看我的演示项目 可以在此处下载 http s000 tinyupload com index php file id 07311576247413689572 http s0
  • 如何使用 Unity 在 Android 设备上以各种宽高比显示游戏的相同部分?

    我从 Libgdx 引擎转向 Unity 是一名初级程序员 我尝试在 Unity 中为 Android 和 iOS 设备制作游戏 但在宽高比 分辨率缩放方面遇到问题 在 Libgdx 中 如果您开发了一些东西 您可以指定 默认 分辨率 并且
  • prepareForSegue 和代表

    我有一个有两个 segue 的应用程序 在其中一个 Segue 中 当前视图控制器成为委托 而另一个则不是 void prepareForSegue UIStoryboardSegue segue sender id sender if s
  • 使用prefersLargeTitles 和 UITableView 平滑滚动

    我在使用时遇到了滚动问题prefersLargeTitles并添加了UITableView 如果我设置prefersLargeTitles在导航控制器中 其根是UITableViewController一切都很好 导航大标题的滚动方式与我们
  • 找不到导航对象。您的组件是否位于导航器屏幕内?

    在我下面的代码中 当我使用 useNavigation 时 它会给出像我的问题一样的错误 如何使用useNavigation 请任何人都可以解决此错误 错误 找不到导航对象 您的组件是否位于导航器屏幕内 我从这里跟踪了代码https rnf
  • 编写支持 iOS 3.1.3 和 iOS 4.x 的 iOS 应用程序时的陷阱

    我想编写一个可以在 iOS 3 1 3 到 iOS 4 1 上运行的应用程序 我知道如何设置部署目标和基础 SDK 阅读 Apple 文档后 它很大程度上依赖于检查类是否可用和 或实例是否响应特定选择器 现在我的问题是 如果 Apple 从
  • 如何保存 1 个 xcode 项目中的所有构建设置并在其他 xcode 项目上使用它们?

    我使用 xcode 4 5 和 cordova phonegap 来构建我的应用程序 我投入了大量时间来获取适合我的 Xcode 项目的构建设置 并且我想在我正在构建的多个应用程序上重用这些设置 我正在寻找是否有一种快速的方法来导出这些设置
  • 使用 JavaScript 从 URL 变量读取来加载不同的 CSS 样式表

    我试图在我的 WordPress 博客上使用两个不同的样式表 以便在通过 Web 访问页面时使用一个样式表 而在通过我们的 iOS 应用程序访问博客内容时使用另一个样式表 现在 我们将 app true 附加到来自 iOS 应用程序的 UR
  • 应用程序图标未刷新

    我更改了新版本应用程序中的图标图像 并且我在设备中安装了旧版本应用程序 然后我安装了新版本 它在 iOS 5 中运行良好 但在 iOS 6 中 图标没有刷新 它仍然显示旧版本图标 徽标 如果没有安装旧版本应用程序 该设备在 iOS 5 和

随机推荐