どれくらいの数のアイテムがストレスなく処理できるか。
ユーザー側の操作に問題がでるようであれば、
ページングなどそれなりの処理が必要です。
まず、シンプルに試す。
以下、1ファイルコピペして Canvas で試せます。
あれ、Gist 埋め込みのスタイル変わったか。まあいいか。
雰囲気、問題ないのは、1000個ぐらいですかね、少なめで。
なんせ、@Query
や fetch()
が1万個くらいになると重い。
これを元に改修していきます。
データ数は10万件にしてやってみます。
🤔 大量データのインポート
バックグラウンドで @ModelActor
を使います。
@ModelActor
actor ItemService {
func generate(size: Int) async {
for i in 0 ..< size {
modelContext.insert(
Item(i: i, s: String(format: "%04d", i))
)
if ((i + 1) % 1_000 == 0) {
try? modelContext.save()
try? await Task.sleep(for: .milliseconds(1))
}
}
try? modelContext.save()
}
}
View の init()
や .onAppear()
で。
ItemListView()
.onAppear {
Task {
await ItemService(modelContainer: modelContext.container)
.generate(size: 100_000)
}
20秒くらいかかりました。
環境に依りますが、5000件/秒ぐらいです。
【SwiftUI】SwiftData でスレッドセーフにバックグラウンドでデータを扱う 🔄 #Swift #ios #エンジニア #SEShttps://t.co/wXk51CBrmZ
— chanzmao (@maochanz) June 25, 2024
👉 SwiftData でのバックグラウンドでの大量データインサート #SwiftUI - Qiita
🤔 最終要素の表示を検出する
1000 個ずつ読み込みます。
1000個目を表示したら次の1000個を読み込みます。
この記述がシンプルで良さげです。
ScrollView {
LazyVStack {
ForEach(items) { item in
Text("\(item.i) | \(item.s)")
.onAppear {
if item == items.last { // *
print("load next!")
}
}
}
}
}
【SwiftUI】TextField で debounce | Debouncing TextField https://t.co/OwrPgSEH3Y #プログラミング #ios
— chanzmao (@maochanz) April 27, 2024
LazyVStack って単純に追加を繰り返すだけでもストレスなく動くんですね !
ちょっと、引っかかる感じもあるけどタイミング次第か。
🤔 データの分割読み込みと追加
データが1000個以上が遅い重いの原因は「読み込み」です。
シンプルなデータクラスでも遅い。
「@Query
の引数がダイナミックでない」ようなので、
@Observable
クラスで対応します。
最終アイテムが表示されたときに、1000個ずつ追加します。
検索文字列のセットには Predicate
を、
抽出のオフセットや限度数、並び順は FetchDescriptor
を使います。
【SwiftData】@Query の引数と Descriptor の関係
👉 https://t.co/4xwuLYq4lB#swift #プログラミング学習— chanzmao (@maochanz) March 26, 2024
【SwiftData】@Query の検索条件や並び順を変更する
👉 https://t.co/gyefBkZKM7 #Swift #ios— chanzmao (@maochanz) June 24, 2024
🤔 @Query で Observe しながら fetchCount() を使う
話しがそれますが、こんな方法も試す。
【SwiftData】@Query で大量データをカウントする - バックグラウンドの進捗状況 #Swift #SwiftUI #SwiftDatahttps://t.co/TMb2XT12o1
— chanzmao (@maochanz) July 2, 2024
private static var fetchDescriptor: FetchDescriptor<Item> {
var fd = FetchDescriptor<Item>()
fd.fetchLimit = 1
return fd
}
@Query(fetchDescriptor) private var zo: [Item]
private var count: Int {
zo.isEmpty ? 0 : try! modelContext.fetchCount(FetchDescriptor<Item>())
}
🤔 スレッドの切り替えとスレッド間の受け渡し
いまいち馴染めず使いこなせないのが @MainActor
。
Strict Concurrency Checking を Complete と最も厳しくしておいて進みます。
【Swift】Strict Concurrency Checking の設定 https://t.co/wmXyJ8ipOv #Qiita
— chanzmao (@maochanz) June 25, 2024
てか、自在に Swift バージョンを乗り越えての スレッド自在に使えるやつがどれくらいいるのか ?
そもそも、言語側は、開発側が意図的にスレッドの切り替えをさせない方向で進んるように見えるのだが。
【Swift】concurrency をマスターするための一つのきっかけ|chanzmao https://t.co/4R1ZXkXG9g #zenn #swift #プログラミング初心者
— chanzmao (@maochanz) July 4, 2024