CoreData 中的异步读取 - 使用 newBackgroundContext + FetchRequest 与 newBackgroundContext + NSAsynchronousFetchRequest 的区别?

2024-04-08

似乎有两种方法可以在 CoreData 中执行异步读取,而不会阻塞主线程 UI。


新的BackgroundContext + NSFetchRequest

来源 :https://www.advancedswift.com/core-data-background-fetch-save-create/ https://www.advancedswift.com/core-data-background-fetch-save-create/

// Create a new background managed object context
let context = persistentContainer.newBackgroundContext()

// If needed, ensure the background context stays
// up to date with changes from the parent
context.automaticallyMergesChangesFromParent = true

// Perform operations on the background context
// asynchronously
context.perform {
    do {
        // Create a fetch request
        let fetchRequest: NSFetchRequest<CustomEntity>

        fetchRequest = CustomEntity.fetchRequest()
        fetchRequest.fetchLimit = 1

        let objects = try context.fetch(fetchRequest)

        // Handle fetched objects
    }
    catch let error {
        // Handle error
    }
}

新的BackgroundContext + NSAsynchronousFetchRequest

Source: https://www.marcosantadev.com/coredata_crud_concurrency_swift_2/ https://www.marcosantadev.com/coredata_crud_concurrency_swift_2/

let privateManagedObjectContext = persistentContainer.newBackgroundContext()

// Creates a fetch request to get all the dogs saved
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Dog")

// Creates `asynchronousFetchRequest` with the fetch request and the completion closure
let asynchronousFetchRequest = NSAsynchronousFetchRequest(fetchRequest: fetchRequest) { asynchronousFetchResult in

    // Retrieves an array of dogs from the fetch result `finalResult`
    guard let result = asynchronousFetchResult.finalResult as? [Dog] else { return }

    // Dispatches to use the data in the main queue
    DispatchQueue.main.async {
        // Do something
    }
}

do {
    // Executes `asynchronousFetchRequest`
    try privateManagedObjectContext.execute(asynchronousFetchRequest)
} catch let error {
    print("NSAsynchronousFetchRequest error: \(error)")
}

但是,请注意,如果我要启用标志,上面的代码将不幸地导致致命错误-com.apple.CoreData.ConcurrencyDebug 1。到目前为止,我还没有一个好的解决方案。更详细的内容请参考为什么我在这个最简单的 NSAsynchronousFetchRequest 用例中获得 Multithreading_Violation_AllThatIsLeftToUsIsHonor? https://stackoverflow.com/questions/70538970/why-i-am-getting-multithreading-violation-allthatislefttousishonor-for-this-simp


我可以知道,它们之间有什么区别newBackgroundContext + NSFetchRequest vs newBackgroundContext + NSAsynchronousFetchRequest?

我应该如何选择一种而不是另一种?谢谢。


1. 关于__Multithreading_Violation_AllThatIsLeftToUsIsHonor__例外:

这个线程中有详细的讨论:
CoreData 异步获取导致并发调试器错误 https://stackoverflow.com/questions/31728425/coredata-asynchronous-fetch-causes-concurrency-debugger-error

一致认为这是 CoreData 中的一个错误。
有一个错误报告:https://openradar.appspot.com/30692722 https://openradar.appspot.com/30692722截至撰写本文时,该网站已经 8 年后仍然开放。

2.如何正确使用NSAsynchronousFetchRequest

该 API 于 2014 年推出,并在 WWDC 视频中进行了讨论225_sd_whats_new_in_core_data https://devstreaming-cdn.apple.com/videos/wwdc/2014/225xxgzhqylosff/225/225_hd_whats_new_in_core_data.mov?dl=1.
没有提到是否NSAsynchronousFetchRequest应该在主(视图)上下文或后台上下文上使用。

我使用以下命令查看了几个随机实现NSAsynchronousFetchRequest在 GitHub 上,我找到了主要上下文和背景上下文的示例。

一件事你must do然而,当使用后台上下文时,将提取执行包装在perform block (文档 https://developer.apple.com/documentation/coredata/using_core_data_in_the_background).
在您链接的文章和上面摘录的示例中,缺少此内容!
它应该是这样的:

privateManagedObjectContext.perform {
    do {
        try privateManagedObjectContext.execute(asynchronousFetchRequest)
    } catch let error {
        print("error trying to fetch saving objects:", error.localizedDescription)
    }
}

同一篇文章还有另一个潜在问题,因此请持保留态度:

DispatchQueue.main.async {
    // here the objects in result (belongs to private context) are
    // accessed on the main queue – the whole point is to *not* do that!
    // one might get away with it because it is only read access to id
    // but good luck debugging this...
    let dogs: [Dog] = result.lazy
        .flatMap { $0.objectID }
        .flatMap { mainManagedObjectContext.object(with: $0) as? Dog }
    // ...

我理解的方式NSAsynchronousFetchRequest是它最好在主上下文中使用,其目的实际上是向您隐藏后台上下文业务。

So: mainContext + NSAsynchronousFetchRequest

3. 我应该如何选择?

在我看来,这NSAsynchronousFetchRequest创建的初衷是为了简化我们的异步核心数据获取。为此,您很可能会利用它来发挥自己的优势,特别是当您需要处理进度和取消时。

但是我可能不会在我的项目中使用它,因为

  • 文档很少
  • 它维护得不好(永远存在错误)
  • 它没有很好地适应(例如流行且优秀的 Core Data 包装器核心商店 https://github.com/JohnEstropia/CoreStore不使用它)

最后一个想法 - 在进行异步获取之前,请确保您确实需要它。首先优化查询、数据模型或批处理设置的性能可能会更好。

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

CoreData 中的异步读取 - 使用 newBackgroundContext + FetchRequest 与 newBackgroundContext + NSAsynchronousFetchRequest 的区别? 的相关文章

  • 如何在IOS中的UIStackView中设置权重

    UIStackView与安卓类似LinearLayout但我不知道如何设置子视图的权重 假设我有一个垂直的UIStackView and 3 UIImageView就在里面 我想连续设置权重3 6 1UIImageViews 我怎么做 UI
  • 无法构建 Saurik 的 ldid 实用程序

    当我执行此命令 make sh 时 我遇到这些错误 构建用于越狱调整开发的 ldid 实用程序 Bilals Mac ldid billy make sh g arch i386 arch x86 64 arch ppc arch armv
  • 将永久字符添加到 UITextField

    有没有办法将字母永久添加到 UITextField 中 用户无法删除它 我想添加一个字符 用户无法删除它 但他们仍然可以在之后添加字母 Cheers 附注这是适用于 iOS 的 A UITextField有一个名为 应该更改范围内的字符 的
  • 如何打开定位服务

    当有人第一次拒绝时 如何从实际应用程序重新打开定位服务 我可以选择关闭或打开它 您只能提示他们在屏幕上打开定位服务 如下所示 UIApplication sharedApplication openURL NSURL URLWithStri
  • 如何替换已弃用的方法dispatch_get_current_queue()? [复制]

    这个问题在这里已经有答案了 我正在 iOS 5 中使用 xmppframework 开发一个聊天应用程序 它工作得很好 但我将 Xcode 更新到 4 5 1 将 iOS 5 更新到 iOS 6 将 Mac OS 更新到 10 7 5 但由
  • 如何在 iOS 9 上可靠地检测是否连接了外部键盘?

    在 iOS 9 之前 确定是否连接外部键盘的最可靠方法是监听UIKeyboardWillShowNotification并使文本字段成为第一响应者 如中所述这个问题 https stackoverflow com questions 289
  • 使用完成处理程序在 Swift 中调用连续动画

    我正在制作一个可以显示化学反应动画的应用程序 每个原子都是一个 SCNSphere 并通过 SCNActions 进行动画处理 我尝试使用 runAction 中的完成处理程序在当前操作完成后调用下一个动画 因为每个原子必须做出很多不同的运
  • 带操作按钮的颤动本地通知

    我在我的 flutter 项目中尝试了 flutter 本地通知插件 它在简单通知上工作正常 但我需要带有操作按钮的通知功能 请帮助我或建议我实现此功能 不幸的是 flutter local notifications 插件尚不支持操作按钮
  • 当我输入字符时,SwiftUI 中的 TextField 失去焦点

    当我在文本字段中输入字符时遇到问题 在练习集视图 我必须重新单击文本框才能输入另一个字符 如果我从文本字段中删除绑定 我可以流畅地输入文本 我认为这与我的演讲者班级和更新集函数重新创建一个集合实例 因为我必须替换数组中两层深处的一些值 Co
  • GeoFire Swift 3 - 保存和更新坐标

    我正在尝试使用 GeoFire 将坐标存储到 Firebase 数据库中 我不确定如何更新新坐标 因为它们每秒都会更改 更新 随着childByAutoId 它正在为每辆自行车生成一个新的唯一 ID 如何引用这个唯一的自行车 ID 例如 用
  • 在 Swift 中从 UIScrollView 创建 PDF 文件

    我想从 UIScrollView 的内容创建一个 PDF 文件 func createPdfFromView aView UIView saveToDocumentsWithFileName fileName String let pdfD
  • 如何在 React Native 中构造 POST 请求主体,而不是使用字符串化的 json,而是使用 json?

    我正在努力用 React Native 替换一些本机代码 预期的 POST 请求 在AFNetworking in Charles应该是这样的 代码片段 NSError err NSData paramData NSJSONSerializ
  • 作为!与 Swift 中 Xcode 6.3 中的 as 运算符对比

    Xcode 6 3 使 Swift 发生了很大变化 我必须更换每个应用程序中的数十个位置as gt as 为什么 现在有什么规则 在 Swift 1 2 之前 as运算符可用于执行两种不同类型的转换 具体取决于要转换的表达式的类型及其要转换
  • AVAssetExportSession 为零 iPhone 7 - Plus 模拟器

    AVAssetExportSession在 iPhone 6 及以下版本上运行良好 但在 iPhone 7 iPhone 7 Plus 模拟器上运行不佳 Xcode 8 0 这段代码return nil在exportSession中 当在i
  • ios水平居中约束问题?

    I am having hard time in learning constraints auto layout in iOS I have used any width any height I have a storyboard sc
  • 在 iOS 中,如何创建一个始终位于所有其他视图控制器之上的按钮?

    无论是否呈现模态或用户执行任何类型的转场 有没有办法让按钮在整个应用程序中 始终位于顶部 而不是屏幕顶部 有什么方法可以让这个按钮可拖动并可捕捉到屏幕上吗 我正在以苹果自己的辅助触摸作为此类按钮的示例 您可以通过创建自己的子类来做到这一点U
  • 如何让按钮闪烁?

    我试图在扫描正确时将按钮的颜色 只是闪烁 闪烁 更改为绿色 在出现问题时将按钮的颜色更改为红色 我可以用这样的视图来做到这一点 func flashBG UIView animateWithDuration 0 7 animations s
  • 什么是 WKWebView 中的 WKErrorDomain 错误 4

    fatal error LPWebView encounters an error Error Domain WKErrorDomain Code 4 A JavaScript exception occurred UserInfo 0x7
  • UIView晃动动画

    我试图在按下按钮时使 UIView 摇动 我正在调整我找到的代码http www cimgf com 2008 02 27 core animation tutorial window shake effect http www cimgf
  • 在 UIScrollview 上显示缩略图的最佳方法是什么(从服务器下载)

    我想在 UIScrollview 如照片应用程序 上显示许多图像 作为缩略图 所有图像将从服务器下载 据我所知 有几种选择 1 通过创建 UIImageviews 然后将它们添加为主滚动视图上的子视图 2 通过子类化一个UIView类 然后

随机推荐