FetchRequest 的 12000 个条目在 macOS 应用程序上非常慢,但不是 iOS 应用程序 - 尽管代码相同(macOS Big Sur 上的 SwiftUI / iOS 14)
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)
编辑(以下原文可忽略)
我仅使用手动提取(仅执行一次)进行了进一步测试。 似乎只是提取请求(仅针对 12000 个实体)本身非常慢。不过,我想知道为什么我应该只针对 macOS 而不是 iOS,因为它是相同的代码?
==========================================
原版post
我正在为 macOS Big Sur/iOS 14 开发一个简单的 SwiftUI 应用程序,它通过 CloudKit 同步“Card”实体(没什么特别的;大约 20 个属性和 7 个关系) .一切正常,但是,在导入(仅)12000 个条目(来自解码的 JSON 文件)后,macOS 应用程序(但不是 iOS 应用程序)变得无法使用,即 freezes/has 一个非常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”如下所示(为了更好的易读性而缩写):
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' 不应该用于取消存档,并将在未来的版本中删除”。 =49=] 因为我还在 Card 实体上使用一些 [String]-Transformable-Properties。稍后我会解决这个问题,但是由于这个警告似乎一直在显示,我想知道@FetchRequest 是否不断 fetches/evaluates all 个实体?此外,我假设显示的大量警告只会影响 Xcode 的 CPU 用法?
我解决了这个问题;似乎确实是警告“'NSKeyedUnarchiveFromData' 不应该用于 un-archiving 并将在未来的版本 中删除”导致 CPU用法。 将“NSSecureUnarchiveFromDataTransformer”设置为所有数据库实体的所有 [String]-Transformable-Properties 后,问题就消失了。
编辑(以下原文可忽略)
我仅使用手动提取(仅执行一次)进行了进一步测试。 似乎只是提取请求(仅针对 12000 个实体)本身非常慢。不过,我想知道为什么我应该只针对 macOS 而不是 iOS,因为它是相同的代码?
==========================================
原版post
我正在为 macOS Big Sur/iOS 14 开发一个简单的 SwiftUI 应用程序,它通过 CloudKit 同步“Card”实体(没什么特别的;大约 20 个属性和 7 个关系) .一切正常,但是,在导入(仅)12000 个条目(来自解码的 JSON 文件)后,macOS 应用程序(但不是 iOS 应用程序)变得无法使用,即 freezes/has 一个非常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”如下所示(为了更好的易读性而缩写):
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' 不应该用于取消存档,并将在未来的版本中删除”。 =49=] 因为我还在 Card 实体上使用一些 [String]-Transformable-Properties。稍后我会解决这个问题,但是由于这个警告似乎一直在显示,我想知道@FetchRequest 是否不断 fetches/evaluates all 个实体?此外,我假设显示的大量警告只会影响 Xcode 的 CPU 用法?
我解决了这个问题;似乎确实是警告“'NSKeyedUnarchiveFromData' 不应该用于 un-archiving 并将在未来的版本 中删除”导致 CPU用法。 将“NSSecureUnarchiveFromDataTransformer”设置为所有数据库实体的所有 [String]-Transformable-Properties 后,问题就消失了。