问题描述
我在使用包含大量数据的 SwiftUI List
时遇到了性能问题。我创建了一个演示应用程序只是为了展示 500_000 String
秒的问题并显示其中一个的尾随操作,cpu 达到 100% 几秒钟,这是完全无法使用的。我还继续包装 UITableView
以在 SwiftUI 上使用相同的数据集(相同的 50 万个 String
)使用它,并立即显示尾随操作。
有什么方法可以加快 SwiftUI List
上的速度,还是这只是框架的限制?
我只需更改名为 listKind
的 var 即可轻松测试这两种实现,示例代码如下:
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])
}
}
}