LoginSignup
0
1

著名なサイトのこのコード。

actor BackgroundImporter {
    var modelContainer: ModelContainer

    init(modelContainer: ModelContainer) {
        self.modelContainer = modelContainer
    }

    func backgroundInsert() async throws {
        let modelContext = ModelContext(modelContainer)

        let batchSize = 1000
        let totalObjects = 100_000

        for i in 0..<(totalObjects / batchSize) {
            for j in 0..<batchSize {
                // try await Task.sleep(for: .milliseconds(1))
                let issue = Movie(title: "Movie \(I * batchSize + j)", cast: [])
                modelContext.insert(issue)
            }

            try modelContext.save()
        }
    }
}

ここの部分。

// try await Task.sleep(for: .milliseconds(1))

説明としては以下のように書いています。

It has a commented-out 1-millisecond pause between each object insertion – the code goes as fast as possible, but if you want to throttle your inserts you should uncomment that line.

各オブジェクトの挿入の間にコメントアウトされた 1 ミリ秒の一時停止があります。コードは可能な限り高速に実行されますが、挿入を抑制したい場合は、その行のコメントを解除する必要があります。

怪しいですよね。

試してみます。

🤔 やってみたが

似たコードがあったのでデータ10万行で試してみました。

少し思ったことをいくつか。

🧑🏻‍💻 なぜこのコメントアウト行を書いたのか

自然に考えると不要ですよね。

「挿入を抑制したい場合」の意味については、

著者は書いてません。

が、コメントアウトのままでは、

途中で画面に反映されなかった。

実行環境に依る話しなのかもしれません。

表面的にデリケートな奥深い話しなのでしょうか。

🧑🏻‍💻 sleep のタイミング

数十万レコードを処理してみたのですが、遅すぎる。

どっちみち、メインスレッドに反映のタイミングは、

try modelContext.save()

なので、

for i in 0..<(totalObjects / batchSize) {
    for j in 0..<batchSize {
        let issue = Movie(title: "Movie \(I * batchSize + j)", cast: [])
        modelContext.insert(issue)
    }
    
    try modelContext.save()
    try await Task.sleep(for: .milliseconds(1)) // *
}

のが実行時間的には早いし、

save() のタイミングで画面反映もされる。

まさか、insert の順序が交差してしまうのか ?

🧑🏻‍💻 @ModelActor を使う

こここそ使うところなんじゃね?

@ModelActor
actor BackgroundImporter {
    func backgroundInsert() async throws {
        let batchSize = 1000
        let totalObjects = 100_000

        for i in 0..<(totalObjects / batchSize) {
            for j in 0..<batchSize {
                let issue = Movie(title: "Movie \(I * batchSize + j)", cast: [])
                modelContext.insert(issue)
            }

            try modelContext.save()
            try await Task.sleep(for: .milliseconds(1))
        }
    }
}

呼び出し側。

@Environment(\.modelContext) private var modelContext

private var importer: BackgroundImporter {
    BackgroundImporter(modelContainer: modelContext.container)
}

actor 側で、いきなり、modelContext を使ってますが、

イニシャライザーなどマクロが書き出してますので

Xcode から expand で見ることができます。

🤔 まとめ

などやっていると、怖くなってきます SwiftData。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1