提问人:Alex Filatov 提问时间:11/6/2023 最后编辑:Alex Filatov 更新时间:11/6/2023 访问量:70
调用 objectWillChange.send() 会产生性能问题
Calling objectWillChange.send() produce performance issues
问:
我有一个具有嵌套对象结构的项目
Project -> Panels -> Layers
我有 SettingsView,我在其中更新任何这些结构的不同属性。
每次更新时,我都必须打电话才能立即查看 View 中的更改。
如果我有少量对象,它可以正常工作并且不会产生性能问题。但是,如果对象数量增加,则会出现性能问题。objectWillChange.send()
我的代码示例如下:
class SelectedProjectHolder: ObservableObject {
@Published var projects: [Project] = []
@Published var selectedProject: Project? = nil
.....
func updateTextLayerColor(for textLayer: TextLayer, newColor: Color) {
guard let selectedProject = selectedProject else {
return
}
for (panelIndex, panel) in selectedProject.panels.enumerated() {
if let layerIndex = panel.textLayers.firstIndex(where: { $0.id == textLayer.id }) {
selectedProject.panels[panelIndex].textLayers[layerIndex].color = newColor
objectWillChange.send()
return
}
}
}
....
}
struct MainApp: App {
let selectedProjectHolder = SelectedProjectHolder()
var body: some Scene {
WindowGroup {
ContentView(lastSaveTime: lastSaveTime)
.environmentObject(selectedProjectHolder)
}
.commands {
SidebarCommands()
}
}
}
// example of Panel view with passed data:
struct PanelView: View {
@EnvironmentObject var selectedProjectHolder: SelectedProjectHolder
@Binding var panel: Panel
...
}
我错过了什么,为什么它不显式调用就不起作用?objectWillChange.send()
有没有办法在我更改属性时立即查看更改而无需调用?objectWillChange.send()
selectedProject
SelectedProjectHolder
答:
1赞
malhal
11/6/2023
#1
代码结构不正确。该对象应仅保存项目,并应负责加载和保存。所选项目应位于 ProjectsView 中。或者,在公共父项中状态,将@Binding传递给可以更改选择的子视图,并作为 let 传递给仅读取当前选择的子视图。@State
创建一个计算属性,将所选内容转换为颜色,并将其传递给子 View init。当传入不同的颜色时,将调用正文。不需要对象或 objectWillChange,这个基本的更改检测已经内置在 SwiftUI 视图结构中。
示例代码:
struct ProjectsView: View {
@EnvironmentObject var projectsStore: ProjectsStore
@State var selectedProject: Project? = nil
// transform from the selection to the color
// this is called every time the selection changes
var textLayerColor: Color {
guard let selectedProject = selectedProject else {
return defaultColor
}
...
// find the color you want
...
return newColor
}
var body: View {
...
ForEach(projectsStore.projects) { project in
// pass computed property into child View
PanelView(color: textLayerColor)
...
评论
0赞
Alex Filatov
11/6/2023
感谢您的回复!我试着把我的头缠绕在它身上。据我了解,我仍然可以使用@Binding。但我不明白为什么视图不显示更新的视图,除非我调用?P.S. 如果有帮助,我添加了一些 PanelView 定义objectWillChange.send()
0赞
malhal
11/6/2023
正如我所说,代码结构不正确,所以你有某种技巧来使其工作。最好像我的答案一样正确构建它,如果您需要示例代码,请告诉我。
0赞
Alex Filatov
11/6/2023
是的,一个例子会很棒,请分享!
0赞
malhal
11/6/2023
OK 添加了一个示例,说明如何使用 State 进行选择并使用 Computed 属性转换数据
评论
Project
SelectedProjectHelper
View
Project
class
@EnvironmentObject
View
@Binding var