【问题标题】:SwiftUI toolbar action with StateObject causes frame rate to dropStateObject 的 SwiftUI 工具栏操作导致帧速率下降
【发布时间】:2021-06-25 12:50:44
【问题描述】:

我有一个相当直接的 swift UI 视图,它允许您拖动形状。

我注意到,只要我有一个工具栏动作,它的动作捕捉我观察到的对象grid,帧速率就会显着下降。

这是下面的代码,状态对象当前处于操作中 (grid.snapEnabled.toggle())

func makeItem() -> SGGridItem {
    SGGridItem(id: UUID(), rect: CGRect(origin: .init(x: 250, y: 250), size: .init(width: 50, height: 50)))
}

struct ContentView: View {
    @StateObject var grid = SGGridState(items: [
        makeItem(),
        makeItem(),
        makeItem(),
        makeItem(),
        makeItem(),
        makeItem()
    ])
    
    var body: some View {
        SGGridCanvas(grid:grid) {
            SGGridView(grid: grid)
        }.frame(maxWidth:.infinity, maxHeight: .infinity)
        .toolbar(content: {
            ToolbarItem(placement: .principal) {
                Button(action: { grid.snapEnabled.toggle() }) {
                    Image(systemName: "square.grid.3x3.topleft.fill").opacity(grid.snapEnabled ? 1 : 0.5)
                }
            }
        })
        .onAppear {
            grid.globalGridItemPadding = 5
            grid.globalGridItemCornerRadius = 5
        }
    }
}

在此 GIF 中,您可以看到明显的滞后,因为被拖动的形状跟随在鼠标光标后面。

但是,如果我现在将工具栏操作更改为像这样的空闭包

            ToolbarItem(placement: .principal) {
                Button(action: { }) {
                    Image(systemName: "square.grid.3x3.topleft.fill").opacity(grid.snapEnabled ? 1 : 0.5)
                }
            }

然后如您所见,视图现在按预期执行(形状完全跟随鼠标)。

在闭包中捕获状态对象时,我打算在这里做些什么特别的事情吗?

这是 swift UI 中固有的性能问题,还是我需要以某种方式改变我的结构?

【问题讨论】:

    标签: swift macos swiftui


    【解决方案1】:

    没有太多运气直接解决这个问题。

    唯一可行的方法是使用通知中心将状态对象与操作分离。

    下面的方法奏效了。

    public extension Notification.Name {
        static let SGGridStateSnapEnableToggle = Notification.Name("SGGridStateSnapEnableToggle")
    }
    
    public class SGGridState: ObservableObject {
        @Published public var snapEnabled: Bool = true
    
        init() {
            NotificationCenter.default.addObserver(self, selector: #selector(self.snapEnabledToggle), name: .SGGridStateSnapEnableToggle, object: nil)
        }
        
        @objc public func snapEnabledToggle() {
            snapEnabled.toggle()
        }
    }
    
    

    然后在原始工具栏操作中,我们可以发布通知,状态对象会选择它并切换它自己的 Published 属性。

    ToolbarItem(placement: .principal) {
                    Button(action: {
                        NotificationCenter.default.post(name: .SGGridStateSnapEnableToggle, object: nil)
                    }) {
                        Image(systemName: "square.grid.3x3.topleft.fill")
                    }
                }
    

    不理想,但可以。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多