1
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Xcode 16.1 & Swift 6: UNUserNotificationCenter でクラッシュする問題を非同期APIで解決する

Last updated at Posted at 2024-11-17

はじめに

Xcode 16.1 で Swift 6 環境を使用していると、UNUserNotificationCenter.current().requestAuthorization を使った通知許可リクエストでクラッシュが発生する場合があります。しかもエラーログに原因が出力されずAIに聞いても解決できませんでした。最新の環境限定のエラーはAIはそれらしい返答は返してくるので余計に時間かかりますよね。

この記事では、この問題の原因と、その解決方法を解説します。

問題の概要

以下のコードは、通知許可をリクエストする一般的な方法ですが、このコードを Swift 6 環境で実行すると、クラッシュが発生します。

@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate

func configureNotification() {
    let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
    UNUserNotificationCenter.current().requestAuthorization(options: authOptions) { granted, error in
        if let error = error {
            print("通知許可エラー: \(error.localizedDescription)")
        } else if granted {
            print("通知が許可されました")
        } else {
            print("通知が拒否されました")
        }
    }
}

クラッシュの原因

Appleの DTS Engineer によると、このクラッシュの原因は、Swift 6 のコンパイラがクロージャの実行スレッドを誤ってメインアクターと認識してしまうことにあります。

この問題により、メインアクター上で実行されていないとクラッシュが発生します。

解決方法: 非同期APIの利用

この問題を解決するには、UNUserNotificationCenter非同期関数版 を使用します。

private func configureNotification() {
    let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]

    Task {
        do {
            // 非同期で通知許可をリクエスト
            let granted = try await UNUserNotificationCenter.current().requestAuthorization(options: authOptions)
            if granted {
                print("通知が許可されました")
                DispatchQueue.main.async {
                    UIApplication.shared.registerForRemoteNotifications()
                }
            } else {
                print("通知が拒否されました")
            }
        } catch {
            print("通知許可エラー: \(error.localizedDescription)")
        }
    }
}

解説

ポイント1: 非同期処理でクラッシュを回避

  • Task を利用して非同期コンテキストを作成し、await を使用して非同期関数を安全に呼び出します。
  • これにより、Swift 6 のメインアクター関連のバグを回避できます。

ポイント2: メインスレッドでの操作

通知が許可された後の UIApplication.shared.registerForRemoteNotifications() はメインスレッドで実行する必要があるため、DispatchQueue.main.async を使用しています。

関連リンク

1
3
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
1
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?