我在使用 SwiftUI 的 List
显示大量数据时遇到了性能问题。我创建了一个演示应用程序来展示使用 500,000 个 String
数据集的问题,并显示一个跟随操作,当操作其中一个字符串时,CPU 占用率会达到 100%,不可用。我还尝试将 UITableView
包装成 SwiftUI 组件,使用同样的数据集(500,000个 String
),并且跟随操作会立即显示。
是否有任何方法可以提高 SwiftUI List
的速度,或者这只是该框架的限制?
我已经将测试两种实现方式变得非常容易,只需更改名为 listKind
的变量,下面是示例代码:
import SwiftUI
@main
struct LargeListPerformanceProblemApp: App {
var body: some Scene {
WindowGroup {
NavigationView {
ContentView().navigationBarTitleDisplayMode(.inline)
}
}
}
}
enum ListKind {
case slow
case fast
}
struct ContentView: View {
var listKind = ListKind.slow
var items: [String]
init() {
self.items = (0...500_000).map { "Item \($0)" }
}
var body: some View {
switch listKind {
case .slow:
List {
ForEach(items, id: \.self) { item in
Text(item).swipeActions(edge: .trailing, allowsFullSwipe: true) {
Button("Print") {
let _ = print("Tapped")
}
}
}
}.navigationTitle("Slow (SwiftUI List)")
case .fast:
FastList(items: self.items)
.navigationTitle("Fast (UITableView Wrapper)")
}
}
}
// UITableView wrapper
struct FastList: UIViewRepresentable {
let items: [String]
init(items: [String]) {
self.items = items
}
func makeUIView(context: Context) -> UITableView {
let tableView = UITableView(frame: .zero, style: .insetGrouped)
tableView.dataSource = context.coordinator
tableView.delegate = context.coordinator
return tableView
}
func updateUIView(_ uiView: UITableView, context: Context) {
uiView.reloadData()
}
func makeCoordinator() -> Coordinator {
Coordinator(items: items)
}
class Coordinator: NSObject, UITableViewDataSource, UITableViewDelegate {
var items: [String]
init(items: [String]) {
self.items = items
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
self.items.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .default, reuseIdentifier: nil)
cell.textLabel?.text = self.items[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let printAction = UIContextualAction(style: .normal, title: "Print") { _, _, block in
print("Tapped")
block(true)
}
return UISwipeActionsConfiguration(actions: [printAction])
}
}
}