macOS 应用程序上的 12000 个条目的 FetchRequest 非常慢,但 iOS 应用程序却没有 - 尽管代码相同(macOS Big Sur / iOS 14 上的 SwiftUI)

Posted

技术标签:

【中文标题】macOS 应用程序上的 12000 个条目的 FetchRequest 非常慢,但 iOS 应用程序却没有 - 尽管代码相同(macOS Big Sur / iOS 14 上的 SwiftUI)【英文标题】:FetchRequest for 12000 entries extremely slow on macOS app but not iOS app - despite code being the same (SwiftUI on macOS Big Sur / iOS 14) 【发布时间】:2020-10-06 22:43:34 【问题描述】:

编辑(以下原文可忽略)

我仅使用手动提取(仅执行一次)进行了一些进一步的测试。 似乎只是获取请求(仅适用于 12000 个实体)本身非常慢。不过,我想知道为什么我应该只针对 macOS 而不是 ios,因为它是相同的代码?

============================================

原帖

我正在为 macOS Big Sur/iOS 14 开发一个简单的 SwiftUI 应用程序,它通过 CloudKit 同步“卡片”实体(没什么花哨的;大约 20 个属性和 7 个关系)。一切正常,但是,在(仅)导入 12000 个条目(从解码的 JSON 文件)后,macOS 应用程序(但不是 iOS 应用程序)变得不可用,即冻结/具有非常高的 CPU 使用率。奇怪的是,如果 UI 上没有显示数据,也会出现此问题,例如具有以下简单视图:

主视图和卡片列表

struct MainView: View     
    @ObservedObject var model: MainViewModel
    @Environment(\.colorScheme) var colorScheme
  
    var body: some View 
        CardList(predicate: Card.predicate(searchText: self.model.searchText,
                                                        pinned: self.model.filterPinned,
                                                        priority: self.model.getPrioritiesAsArray(),
                                                        subjects: self.model.selectedSubjects,
                                                        bundles: self.model.selectedBundles),
                              sortDescriptor: EntrySort(sortType: self.model.sortType, sortOrder:self.model.sortOrder).sortDescriptor,
                              model: self.model)
    
    


struct CardList: View     
    @ObservedObject var model: MainViewModel
    @Environment(\.colorScheme) var colorScheme
    
    @Environment(\.managedObjectContext)
    var context: NSManagedObjectContext
    @FetchRequest(
        entity: Card.entity(),
        sortDescriptors: [
            NSSortDescriptor(keyPath: \Card.id, ascending: false)
        ]
    )
    private var result: FetchedResults<Card>
    
    init(predicate: NSPredicate?,
         sortDescriptor: NSSortDescriptor,
         model: MainViewModel) 
        
        let fetchRequest = NSFetchRequest<Card>(entityName: "Card")
        fetchRequest.sortDescriptors = [sortDescriptor]
        
        if let predicate = predicate 
            fetchRequest.predicate = predicate
        
        _result = FetchRequest(fetchRequest: fetchRequest)
        
        self.model = model
    
  
    var body: some View         
        Text("TEST")        
    


“MainViewModel”如下所示(为了更好的易读性而缩写):

主视图模型

class MainViewModel: ObservableObject     
    @Published var searchText: String = ""
    @Published var selectedSubjects: [Subject]?
    @Published var selectedBundles: [Bundle]?
    @Published var selectedTags: [Tag]?
    
    @Published var filterPinned: Bool? = nil
    @Published var filterPriorityVeryHigh: Bool = false
    @Published var filterPriorityHigh: Bool = false
    @Published var filterPriorityNormal: Bool = false
    @Published var filterPriorityLow: Bool = false
    
    func getPrioritiesAsArray() -> [CardPriority] 
        var res: [CardPriority] = []
        if self.filterPriorityLow  res.append(CardPriority.Low)
        if self.filterPriorityNormal  res.append(CardPriority.Normal)
        if self.filterPriorityHigh  res.append(CardPriority.High)
        if self.filterPriorityVeryHigh  res.append(CardPriority.VeryHigh)
        return res
    
    @Published var sortType = SortType.dateCreated
    @Published var sortOrder = SortOrder.ascending

AppDelegate

import SwiftUI

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate 
    
    var window: NSWindow!
    var coreDataStack = CoreDataStack(modelName: "[Name of Model]")
    var mainViewModel = MainViewModel() 
    
    func applicationDidFinishLaunching(_ aNotification: Notification)   
        coreDataStack.viewContext.automaticallyMergesChangesFromParent = true
        let mainView = MainView(model: mainViewModel)
            .environment(\.managedObjectContext, coreDataStack.viewContext) 
// ...

问题

相同的数据已成功同步到应用程序的 iOS 版本,并且可以在那里显示而没有任何性能问题(使用相同的控件,即 LazyVStack)。然而,由于持续的高 CPU 使用率,macOS 应用程序变得完全无法使用。此外,我看不到任何会不断更改变量并因此触发显示实体的不断刷新(即触发新的获取请求)的东西。

有人知道为什么会出现这个问题吗?

提前感谢您的任何建议!

塞巴斯蒂安

※ 我注意到的一件事是 Xcode 向控制台充斥着警告“NSKeyedUnarchiveFromData'不应该用于取消归档,将在未来的版本中删除”,因为我仍在使用Card 实体上的一些 [String]-Transformable-Properties。我稍后会解决这个问题,但由于这个警告似乎不断显示,我想知道@FetchRequest 是否不断获取/评估所有实体?此外,我假设显示的大量警告应该只会影响 Xcode 的 CPU 使用率?

【问题讨论】:

【参考方案1】:

我解决了这个问题;似乎确实是警告“'NSKeyedUnarchiveFromData' 不应该用于取消归档,并将在未来的版本中删除”导致 CPU 使用率飙升。 将“NSSecureUnarchiveFromDataTransformer”设置为所有数据库实体的所有 [String]-Transformable-Properties 后,问题就消失了。

【讨论】:

以上是关于macOS 应用程序上的 12000 个条目的 FetchRequest 非常慢,但 iOS 应用程序却没有 - 尽管代码相同(macOS Big Sur / iOS 14 上的 SwiftUI)的主要内容,如果未能解决你的问题,请参考以下文章

如何从 CLI 快速重命名 macOS 或 linux 上的文件?

在 Visual Studio Code 上调试 Flutter 应用程序时如何停止 MacOS 上的“钥匙串访问”权限对话框?

如何在 Xamarin 表单 macos 的条目(用于聊天)中添加自定义图像?

MacOs上的Intellij idea高频快捷键总结(2018.1版本)

进阶 | JVM 深入解析(12000 字总结)

如何从 macOS Swift 上的文档目录加载图像?