開発環境
- MacBookAir 2019
- macOS Catarina 10.15
- Xcode 11.2.1
- SwiftUI
概要
Listのfilterで要素数が500以上の時、異常に挙動が遅くなる現象を解決できたので私が行った方法を備忘録的にまとめます。
#ソースコード
struct JsonData: Codable, Equatable,Identifiable{
var id: Int
var itemName: String
var itemPrice: Int
・・・
}
修正前
@EnvironmentObject var jsonData: JsonData
List {
ForEach(jsonData.filter{$0.hasPrefix(searchText)}, id:\.self) {item in
Text(item)
}
}
searchText
は@Stateで定義しており、ここに検索バーに入力された文字が格納されています。searchText
の値が変更されるとその都度Listの中身が更新されます。
この状態でビルドすると、
非常にラグがありますが一応は検索できます(1文字入力すると数秒固まる)。
これはおそらくjsonData
に格納されているデータ数が多いとfilterの処理が律速段階となってしまうためだと思われます。
#解決策
StackOverflow :How do I efficiently filter a long list in SwiftUI?
この投稿を参考に、Listを毎回作り替えることで高速化が実現できました。
修正後
@EnvironmentObject var jsonData: JsonData
if searchText==""{
nonFiltered()
}else{
filtered()
}
////////////////////////////
struct filtered: View {
@EnvironmentObject var jsonData: JsonData
var body: some View {
List {
ForEach(jsonData.filter{$0.hasPrefix(searchText)}, id:\.self) {item in
Text(item)
}
}
}
}
struct nonFiltered: View {
@EnvironmentObject var jsonData: JsonData
var body: some View {
List {
ForEach(jsonData) {item in
Text(item)
}
}
}
}
驚くほど劇的にラグが改善しました。めちゃめちゃヌルヌル動作します。