You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift中如何避免使用swipeAction导致列表加载缓慢?

优化列表SwipeAction中慢查询的方案

问题核心

你的问题在于:hasStar()这类耗时查询会在列表加载阶段为每个Item同步执行,哪怕单个查询仅50ms,数千个元素累计下来也会导致列表加载卡顿;同时滑动操作时该函数还会重复执行,进一步消耗性能。

优化方案

核心思路是避免在View渲染流程中执行同步耗时操作,改用异步预加载+缓存结果,同时只在必要时机触发查询。

方案1:异步预加载+本地缓存

将查询逻辑异步化,用字典缓存每个Item的状态,View直接读取缓存值,彻底避免重复查询。

struct ContentView: View {
    let data = (1...10).map { "Item \($0)" }
    // 缓存每个item的星标状态,默认未标记
    @State private var starStatus: [String: Bool] = [:]
    
    var body: some View {
        VStack {
            List(data, id: \.self) { item in
                Text(item)
                    .swipeActions(edge: .leading) {
                        let isStarred = starStatus[item, default: false]
                        if isStarred {
                            Button {
                                // 更新缓存+实际业务逻辑
                                starStatus[item] = false
                                print("star removed for \(item)")
                            } label: {
                                Label("Remove star", systemImage: "star.slash").font(.title)
                            }.tint(.red)
                        } else {
                            Button {
                                // 更新缓存+实际业务逻辑
                                starStatus[item] = true
                                print("star added for \(item)")
                            } label: {
                                Label("Add star", systemImage: "star").font(.title)
                            }.tint(.green)
                        }
                    }
                    // 初始化时异步加载当前item的状态
                    .task(id: item) {
                        // 仅当未缓存时才查询
                        guard starStatus[item] == nil else { return }
                        let status = await hasStarAsync(item: item)
                        starStatus[item] = status
                    }
            }
        }
    }
    
    // 改为异步函数,模拟耗时查询
    func hasStarAsync(item: String) async -> Bool {
        print("Slow query started for \(item)")
        try? await Task.sleep(nanoseconds: 50_000_000) // 模拟50ms耗时
        print("Slow query finished for \(item)")
        return Bool.random() // 替换为实际查询逻辑
    }
}

方案2:按需加载(针对大数据量列表)

如果列表元素极多,可只对当前可见的Item执行查询,避免一次性加载所有状态:

struct ContentView: View {
    let data = (1...1000).map { "Item \($0)" }
    @State private var starStatus: [String: Bool] = [:]
    // 跟踪已加载过状态的item,避免重复查询
    @State private var loadedItems: Set<String> = []
    
    var body: some View {
        List(data, id: \.self) { item in
            Text(item)
                .swipeActions(edge: .leading) {
                    let isStarred = starStatus[item, default: false]
                    // 按钮逻辑同方案1
                    if isStarred {
                        Button {
                            starStatus[item] = false
                            print("star removed for \(item)")
                        } label: {
                            Label("Remove star", systemImage: "star.slash").font(.title)
                        }.tint(.red)
                    } else {
                        Button {
                            starStatus[item] = true
                            print("star added for \(item)")
                        } label: {
                            Label("Add star", systemImage: "star").font(.title)
                        }.tint(.green)
                    }
                }
                // 当item出现在屏幕时才加载状态
                .onAppear {
                    guard !loadedItems.contains(item) else { return }
                    loadedItems.insert(item)
                    Task {
                        let status = await hasStarAsync(item: item)
                        starStatus[item] = status
                    }
                }
        }
    }
    
    func hasStarAsync(item: String) async -> Bool {
        print("Slow query started for \(item)")
        try? await Task.sleep(nanoseconds: 50_000_000)
        print("Slow query finished for \(item)")
        return Bool.random()
    }
}

关键优化点

  • 异步化:用async/await将耗时操作移至后台线程,不阻塞View渲染。
  • 缓存复用:每个Item仅查询一次,后续直接读取缓存,避免重复消耗。
  • 按需触发:只对可见Item执行查询,大幅减少大数据量场景下的总耗时。

额外建议

如果hasStar()是查询本地数据库(如CoreData):

  • 优先使用批量查询接口,一次性获取多个Item的状态,减少IO次数。
  • 将星标状态直接整合到数据模型中,初始化时批量加载,避免单独查询每个Item。

内容的提问来源于stack exchange,提问作者themadp

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 07:30:58