StateObject 的 SwiftUI 工具栏操作导致帧速率下降
Posted
技术标签:
【中文标题】StateObject 的 SwiftUI 工具栏操作导致帧速率下降【英文标题】:SwiftUI toolbar action with StateObject causes frame rate to drop 【发布时间】: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 中固有的性能问题,还是我需要以某种方式改变我的结构?
【问题讨论】:
【参考方案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")
不理想,但可以。
【讨论】:
以上是关于StateObject 的 SwiftUI 工具栏操作导致帧速率下降的主要内容,如果未能解决你的问题,请参考以下文章
如何防止 SwiftUI 像使用 @StateObject 一样重新初始化我的包装属性?
SwiftUI onChange(of: ...) 更新 StateObject
SwiftUI:如何在父视图中初始化新的 StateObject?
极简示例揭示 SwiftUI 中 @ObservedObject 与 @StateObject 状态的关键区别
极简示例揭示 SwiftUI 中 @ObservedObject 与 @StateObject 状态的关键区别
SwiftUI之深入解析@StateObject@ObservedObject和@EnvironmentObject的联系和区别