ios - 当数据集很大时,SwiftUI List 在显示操作(前导/尾随,contextMenu)方面非常慢

标签 ios swift uitableview swiftui swiftui-list

我在使用 SwiftUI 时遇到性能问题 List有大量数据。我创建了一个演示应用程序只是为了展示 500_000 String 的问题s 并显示其中一个的尾随 Action ,CPU 将在几秒钟内达到 100%,这是完全无法使用的。我也继续包装UITableView使用相同的数据集(相同的 50 万 String 秒)在 SwiftUI 上使用它,并立即显示尾随 Action 。
有什么方法可以加快 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])
        }
    }
}

最佳答案

在仪器中分析似乎 List 为每个项目创建元数据以跟踪更改(例如插入/删除动画)。
Instruments
因此,即使 List 被优化以避免创建不可见的行,它仍然具有直接 UITableView 实现不会产生的元数据开销。
List 开销的另一个演示是改为使用 ScrollView/LazyVStack 组合。我不建议将此作为替代方案(除了视觉差异之外,它会在您向下滚动列表时爆炸),但由于它不进行更改跟踪,因此它也将具有相当快的初始显示。

关于ios - 当数据集很大时,SwiftUI List 在显示操作(前导/尾随,contextMenu)方面非常慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68315292/

相关文章:

ios - 向 Apple App Store 提交 iOS 游戏和应用程序时,如何跳过对 iPad、iPad 2 和 iPad 3 的支持?

objective-c - 表格单元格的背景色

ios - 如何在 Swift 中调用 Objective C UIView 的 initWithFrame

ios - 如何在 View Controller 之间滑动?

ios - 如何在旋转后更改自定义 viewForHeaderInSection 宽度

SwiftUI - 使用 'ObservableObject' 和 @EnvironmentObject 有条件地显示 View

ios - Swift ios 推送通知通知在应用程序打开时不工作,但在应用程序关闭时工作

swift - 减少更新 Realm 值的代码重复

ios - 如何传递与 UITapGestureRecognizer 关联的对象

ios - tableView.deleteRows 崩溃(在 :, 处:)