SwiftUI 在 watchOS 上使用 NavigationLinks 列出性能下降

ben*_*lis 6 ios swift watchkit swiftui

我有一个包含大约 20 个元素的小列表。列表中的每一行都是一个简单的自定义视图,其中有几个标签嵌入在 NavigationLink 中。

struct RunList: View {
    var model: RunModel
    var body: some View {
        List {
            ForEach(model.runs) { run in
//                NavigationLink(destination: RunOverview(run: run)) {. ** seems to have biggest impact on performance. 
                    RunCell(run: run).frame(height: 100)
//                }
            }
        }
        .listStyle(CarouselListStyle())
        .navigationBarTitle(Text("Demo App"))
    }
}
Run Code Online (Sandbox Code Playgroud)

滚动时使用大量 CPU 在 Apple Watch 上运行这个简单的列表会导致丢帧。

当每个列表项都有一个 NavigationLink 作为根视图时,性能似乎明显更差。删除导航链接最多可将 CPU 使用率降低 50%,并极大地提高 Apple Watch Series 2 的性能,但我们需要列表行可点击。

我正在构建的应用程序在布局上与 Apple 制作的 PopQuiz 演示应用程序非常相似https://developer.apple.com/documentation/watchkit/creating_a_watchos_app_with_swiftui

运行上面的示例代码也会出现同样的问题。

我已经在仪器中对其进行了分析,大部分时间似乎都在与布局相关的代码中。

在此处输入图片说明

我很欣赏 Apple Watch 2 现在已经相当老了,但肯定像上面这样的基本列表应该能够运行。设备上的其他系统应用程序运行良好,尽管它们不太可能使用 swiftUI。

我应该注意提示或陷阱吗?

The*_*d27 5

使用一个被激活的 NavigationLink 及其来自 RunCell TapGesture 的信息怎么样?

struct RunList: View {
    var model: RunModel
    @State var activeRun: Run?
    @State var runIsActive = false
    var body: some View {
        List {
            if activeRun != nil {
                NavigationLink(destination: RunOverView(run: activeRun!, isActive: $runIsActive, label: {EmptyView()})
            }
            ForEach(model.runs) { run in
                RunCell(run: run)
                    .frame(height: 100)
                    .onTapGesture {
                        self.activeRun = run
                        self.runIsActive = true
                }
            }
        }
        .listStyle(CarouselListStyle())
        .navigationBarTitle(Text("Demo App"))
    }
}
Run Code Online (Sandbox Code Playgroud)


Cen*_*gen 5

一些想法,

  1. 避免不必要的RunCell. Equatable如果还没有,请使其符合。
struct RunCell: View, Equatable {

    static func == (lhs: RunCell, rhs: RunCell) -> Bool {
       lhs.run == rhs.run // or whatever is equal
    }
...
Run Code Online (Sandbox Code Playgroud)
  1. 也许修复提供的 List 元素的大小

RunCell(run: run).fixedSize(vertical: true).frame(height: 100)

  1. 如果所有 RunCell 视图在属性方面看起来大致相同,请将 List 放在compositingGroup.

NavigationLink 可能也可以完成一些事情,但不确定是什么。Insturments 有一个 SwiftUI 组件,但我不确定它会比 TimeProfiler 提供更多的洞察力。