【问题标题】:Performance Issue with SwiftUI ListSwiftUI 列表的性能问题
【发布时间】:2020-01-05 22:28:43
【问题描述】:

我有一个显示动态 FetchRequest 的结果的列表。

代码运行良好,但结果集更大(例如 3000),当动态谓词更改时,列表的构建速度很慢。

struct ItemList: View {
    @State var startsWith: String = "A"

    var body: some View {
        NavigationView {
            VStack {
                TextField("Startswith", text:$startsWith)
                FilterRequestList(filter: startsWith)
            }
            .navigationBarTitle("Tasks CD")
        } 
    }
} 


struct FilterRequestList: View {
    var fetchRequest: FetchRequest<Item>

    init(filter: String) {
        if filter == "" {
            fetchRequest = FetchRequest<Item>(entity: Item.entity(),
                                              sortDescriptors: [],
                                              predicate: nil)
        } else {
            fetchRequest = FetchRequest<Item>(entity: Item.entity(),
                                              sortDescriptors: [],
                                              predicate: NSPredicate(format: "title BEGINSWITH %@", filter))
        }
    }

    var body: some View {
        VStack {
            Text("Count: \(fetchRequest.wrappedValue.count)")
            List(fetchRequest.wrappedValue, id: \.self) { item in
                Text("\(item.title) ")
            }
        }
    }
}

任何想法,如何改进?

更新: 我发现了什么: 第一个 List 相当快,但是如果 startsWith 状态发生变化,则重新加载非常慢。 我加了

FilterRequestList(filter: startsWith)
    .onAppear(perform: { print("appear F") })
    .onDisappear(perform: { print("disappear F") })

发现,FilterRequestList 并没有消失和重新出现,当过滤器改变时。

这可能是问题吗?怎么可以强迫消遣?

【问题讨论】:

  • 您可以在此处尝试使用阈值方法加载列表项:medium.com/better-programming/…
  • List 构建/绘制的行数不超过屏幕上显示的行数,因此我认为这不是由于 List 而是由于获取/过滤。我建议在修复某些东西之前使用 Instrument 找到真正的瓶颈。
  • 不幸的是,我对 Instruments 不是很有经验。看了一下,我没有注意到性能问题的提示。可能有趣的是:注释掉列表,让它变得更快,所以我的猜测是,列表导致了性能问题。
  • 添加了更新

标签: swift swiftui swiftui-list


【解决方案1】:

感谢 Paul Hudson,我找到了问题的解决方案。 在“https://www.youtube.com/watch?v=h0SgafWwoh8”中,他详细解释了这一点。

你只需要添加修饰符

.id(UUID())

到列表中。

问题是,swiftUI 会尝试检测从旧列表到新列表的任何更改,以便为更改设置动画。 使用修饰符,swiftUI 的旧列表和新列表不是同一个列表(因为 id 总是在变化),所以不需要检测变化。 Swift 可以非常快速地简单地创建新列表。 唯一令人沮丧的是,因此没有动画。

struct ItemList: View {
    @State var startsWith: String = "A"

    var body: some View {
        NavigationView {
            VStack {
                TextField("Startswith", text:$startsWith)
                FilterRequestList(filter: startsWith)
            }
            .navigationBarTitle("Tasks CD")
        } 
    }
} 


struct FilterRequestList: View {
    var fetchRequest: FetchRequest<Item>

    init(filter: String) {
        if filter == "" {
            fetchRequest = FetchRequest<Item>(entity: Item.entity(),
                                              sortDescriptors: [],
                                              predicate: nil)
        } else {
            fetchRequest = FetchRequest<Item>(entity: Item.entity(),
                                              sortDescriptors: [],
                                              predicate: NSPredicate(format: "title BEGINSWITH %@", filter))
        }
    }

    var body: some View {
        VStack {
            Text("Count: \(fetchRequest.wrappedValue.count)")
            List(fetchRequest.wrappedValue, id: \.self) { item in
                Text("\(item.title) ")
            }
            .id(UUID())
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-06-17
    • 1970-01-01
    • 1970-01-01
    • 2019-04-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多