🟣
【Xcode,Swift】スレッドに関する紫色の警告について
以下の警告について解説します。
※今回の記事では、「async/await」のみに対応しています。
「Publishing changes from background threads is not allowed;」
この警告は、バックグラウンドスレッドで行われた処理がUI更新を伴う場合に発生します。Swiftでは、スレッドごとに役割が分担されており、特にUI関連の処理はメインスレッドで実行する必要があります。
スレッドの役割
メインスレッド
メインスレッドは、アプリケーションのUI表示やユーザー操作の応答を処理するスレッドです。UI関連の処理は必ずこのスレッドで実行される必要があります。
バックグラウンドスレッド
バックグラウンドスレッドは、時間がかかる処理を実行するためのスレッドです。これにより、メインスレッドの負担が軽減され、アプリのUIがスムーズに動作します。
サーバーと通信する処理など時間がかかるタスクの場合は、Swiftが自動的にバックグラウンドスレッドに回すことで、UIの表示を遅延することなく、アプリ全体で効率的なタスク処理を実現しています。
警告の原因
この警告が表示されるのは、バックグラウンドスレッドで処理されたタスクが、メインスレッドで行うべきUI関連の処理を実行しようとした場合です。
Swiftでは、バックグラウンドスレッドでUI更新を試みるとこのような問題が発生します。例えば、以下のようなコードは警告の原因になります:
func fetchData() async throws -> String {
// 時間がかかる処理(例: サーバー通信)
try await Task.sleep(nanoseconds: 1_000_000_000) // 1秒待機
return "サーバーから取得したデータ"
}
func performTask() {
Task {
do {
// バックグラウンドでデータ取得
let result = try await fetchData()
// バックグラウンドスレッドでUI更新
label.text = result // 🟣メインスレッド以外でUI操作 → 警告発生
} catch {
print("データ取得エラー: \(error)")
}
}
}
解決方法
UI更新など、メインスレッドで処理する必要があるコードに対して、「@MainActor」を用いることで問題を解決できます。
@MainActor
@MainActorを使用すると、そのメソッドがメインスレッドで実行されることを保証できます。
// @MainActorのメソッド内でUI関連の処理を行うようにする
@MainActor
func updateLabel(with text: String) {
label.text = text
}
func fetchData() async throws -> String {
// 時間がかかる処理(例: サーバー通信)
try await Task.sleep(nanoseconds: 1_000_000_000) // 1秒待機
return "サーバーから取得したデータ"
}
func performTask() {
Task {
do {
// バックグラウンドでデータ取得
let result = try await fetchData()
// メインスレッドでUI更新
await updateLabel(with: result)
} catch {
print("データ取得エラー: \(error)")
}
}
}
@MainActorを使うことで、明示的に「メインスレッドで実行する必要がある」ことを示せます。
Discussion