UIApplication.registerForRemoteNotifications()は、メインスレッドからのみ呼び出す必要があります


81

Xcode 9(iOS 11)は、プッシュ(リモート)通知の登録中にエラー/警告を表示します。

これがエラーメッセージです

ここに画像の説明を入力してください

そしてここにコードがあります、私は試しました:

let center  = UNUserNotificationCenter.current()
center.delegate = self
center.requestAuthorization(options: [.sound, .alert, .badge]) { (granted, error) in
        if error == nil{
              UIApplication.shared.registerForRemoteNotifications()
        }
 }

エラー/警告行:

UIApplication.shared.registerForRemoteNotifications()

これを解決する方法は?


2
エラーメッセージに記載されているように、呼び出しをUIApplication.shared.registerForRemoteNotifications()メインスレッドでラップする必要があります。:) ...メインスレッドでそれを呼び出す方法をグーグルさせる
Duyen-ホア

@HoaなぜmainThreadからこれを行う必要があるのですか?UIとは関係ありません...それとも、数秒後に発生する可能性があり、予期しない動作を引き起こす可能性があるためですか?
ハニー

私はまたしスウィフト4は、私にこのエラーインジケータを示している理由は...、同じ混乱を持っている
Krunal

@SulthanUIApplication.shared.registerForRemoteNotifications()はUIに関連していません(サイレント通知のトークンを取得したときにユーザーにプロンプ​​トを表示しません)。したがって、エラーが示しているは紛らわしいです。ただし、バッジ、アラート、サウンドの登録はUIに関連しているため、メインスレッドから行う方がはるかに優れています...したがって、全体として、ブロック全体center.requestAuthorization(options:...をメインスレッドから行う必要があります...それは理にかなっています
Honey

私はここで見つけることができるこれを拡張する問題を抱えていまし。この質問や他の質問でエラーメッセージに対処してもらいました。
joshLor 2017年

回答:


143

ではswift4

この問題は次の方法で解決できます

DispatchQueue.main.async {
  UIApplication.shared.registerForRemoteNotifications()
}

これがお役に立てば幸いです...


さらに簡単、閉鎖のための必要はありません:DispatchQueue.main.async(execute: UIApplication.shared.registerForRemoteNotifications())
ネイサン

@nathan閉鎖が必要だと思います。私が得たCannot invoke 'async' with an argument list of type '(execute: Void)'あなたの例を使用して、エラーを。
bvpb 2017

4
申し訳ありませんが、タイプミス:DispatchQueue.main.async(execute: UIApplication.shared.registerForRemoteNotifications)execute期待する関数は/タイプの閉鎖は() -> VoidそれほどregisterForRemoteNotifications作品
ネイサン

1
Objectiveの書き方c。
Pooja Srivastava 2017年

5
@PoojaSrivastavadispatch_async(dispatch_get_main_queue(), ^{ //Do stuff });
badhanganesh

46

Objective Cの場合、以下のコードが機能します

    dispatch_async(dispatch_get_main_queue(), ^{
        [[UIApplication sharedApplication] registerForRemoteNotifications];
    });

37

TL; DR:
問題を回避するために、すべてのUI操作はメインスレッドで実行する必要があります。そうしなかった場合、メインスレッドチェッカー(XCode 9で新しく導入されたデバッグ機能)は実行時に問題を引き起こします。したがって、グリッチや実行時の警告を回避するために、コードを以下のようにメインスレッドブロックでラップします。

DispatchQueue.main.async {
    UIApplication.shared.registerForRemoteNotifications()
}

ver。より前のXcodeリリースでは 9、メインスレッドに関連する警告は、コンソール領域にテキストで出力されます。とにかく、オプションで、編集スキームの診断設定でメインスレッドチェッカーを無効にすることができます(推奨されるアプローチではありません)。


説明:

Appleは、UIKitおよびUI要素を操作する他のAPIのランタイムでの問題をチェックするために、XCode9に新しいデバッグオプションを導入しました。メインスレッドブロックなしで、実行時にUIKit APIからUI要素に変更があった場合、UIの不具合やクラッシュが発生する可能性が高くなります。メインスレッドチェッカーは、実行時にこれらの問題をキャッチするためにデフォルトで有効になっています。以下のように、[スキーム編集]ウィンドウでメインスレッドチェッカーを無効にすることができますが、実際には無効にすることはお勧めしません。

メインスレッドチェッカーを無効にする

古いSDKまたはフレームワークを使用している場合、Xcode 9に更新すると、UIKitメソッド呼び出しの一部がメインスレッドでラップされていないため、この警告が表示される場合があります。それらを最新バージョンに更新すると、問題が修正されます(開発者がそれを認識して修正した場合)。

XCode 9ベータリリースノートからの引用:

  • Xcode 9の新機能–メインスレッドチェッカー。
    • バックグラウンドスレッドからのUIAPIの誤用の検出を有効にする
    • メインスレッドで行われていないAppKit、UIKit、およびWebKitメソッド呼び出しを検出します。
    • デバッグ中に自動的に有効になり、スキームエディタの[診断]タブで無効にできます。
    • メインスレッドチェッカーはSwiftおよびC言語で動作します。

1
このXcode9の新しい設定をどのようにしてすばやく習得したのでしょうか。WWDCビデオはまだ出ていません!
ハニー

4
@Honeyリリースノートには通常、必要なすべての変更が含まれています:)
Sulthan 2017

4
@Honeyリリースノートとドキュメントを読む人もいます;
vadian 2017

1
@Honey真剣に、(Xcode)リリースノートを読むことは常に価値があります。
vadian 2017

2
@BadhanGanesh(私は反対票も賛成票もしませんでした)それがあなたの意図したものでない場合は、それを書き直してください...誰かが私に問題Xがあると言っているようなものだからです...そしてあなたはYをすることができます...答えを探しています。それが答えではないことを明確にするよりも単なる説明である場合
Honey

6

エラーメッセージは非常に明確ですregisterForRemoteNotifications。メインスレッドにディスパッチします。

grantedパラメータを使用して、errorそれに応じて処理します

center.requestAuthorization(options: [.sound, .alert, .badge]) { (granted, error) in
        if granted {
              DispatchQueue.main.async {
                  UIApplication.shared.registerForRemoteNotifications()
              }
        } else {
           print(error!)
           // handle the error
        }
}

3

これはSwift4.0で行う正しい方法でもあります

UNUserNotificationCenter.current().delegate = self
        UNUserNotificationCenter.current().requestAuthorization(options: [.alert,.sound,.badge], completionHandler: {(granted,error) in
            if granted{
                DispatchQueue.main.async {
                    application.registerForRemoteNotifications()
                }
            }
        })

1

これが役立つことを願っています

DispatchQueue.main.async(execute: {
  UIApplication.shared.registerForRemoteNotifications()
})

1

これは私のために働いたものです。上記の受け入れられたコメントの@ Mason11987の礼儀。

DispatchQueue.main.async() { code }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.