UIApplication.registerForRemoteNotifications () darf nur vom Hauptthread aufgerufen werden


81

Xcode 9 (iOS 11) zeigt mir einen Fehler / eine Warnung bei der Registrierung für die Push-Benachrichtigung (Remote) an.

Hier ist eine Fehlermeldung

Geben Sie hier die Bildbeschreibung ein

Und hier ist Code, ich habe versucht:

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

Fehler- / Warnzeile:

UIApplication.shared.registerForRemoteNotifications ()

Wie kann ich das beheben?


2
Wie in der Fehlermeldung angegeben, müssen Sie den Aufruf UIApplication.shared.registerForRemoteNotifications()in den Hauptthread einschließen. :) Lassen Sie Google, wie man es im Haupt-Thread nennt ...
Duyen-Hoa

@Hoa warum sollten Sie dies von mainThread aus tun müssen? Es hat nichts mit der Benutzeroberfläche zu tun ... oder liegt es daran, dass es einige Sekunden später auftreten kann und dies zu unerwartetem Verhalten führen kann?
Honey

Ich habe auch die gleiche Verwirrung, warum Swift 4 mir diese Fehleranzeige zeigt ...
Krunal

@Sulthan Das UIApplication.shared.registerForRemoteNotifications()hat nichts mit der Benutzeroberfläche zu tun (Sie werden nicht aufgefordert, Benutzer zu benachrichtigen, wenn Sie ein Token für stille Benachrichtigungen erhalten). Die Zeile, die der Fehler anzeigt, ist also verwirrend. Die Registrierung für die Abzeichen, Warnungen und Sounds hängt jedoch mit der Benutzeroberfläche zusammen und es ist viel besser, dies vom Hauptthread aus zu tun. Insgesamt center.requestAuthorization(options:...muss also der gesamte Block von vom Hauptthread aus ausgeführt werden. Es macht Sinn
Honey

Ich hatte ein Problem, das dies erweitert und hier zu finden ist . Ich hatte die Fehlermeldung in dieser und anderen Fragen angesprochen.
JoshLor

Antworten:


143

In swift4

Sie können dieses Problem mit lösen

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

Hoffe das wird helfen ...


Noch einfacher ist die Schließung nicht erforderlich:DispatchQueue.main.async(execute: UIApplication.shared.registerForRemoteNotifications())
Nathan,

@ Nathan Ich denke, Sie brauchen die Schließung. Ich habe Cannot invoke 'async' with an argument list of type '(execute: Void)'anhand Ihres Beispiels einen Fehler erhalten.
bvpb

4
Entschuldigung, Tippfehler : DispatchQueue.main.async(execute: UIApplication.shared.registerForRemoteNotifications). executeerwartet eine Funktion / Schließung des Typs () -> Voidso registerForRemoteNotificationsfunktioniert
Nathan

1
wie man in Ziel schreibt c.
Pooja Srivastava

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

46

Für Ziel C funktioniert der folgende Code

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

37

TL; DR:
Alle UI-Manipulationen sollten im Haupt-Thread durchgeführt werden, um Probleme zu vermeiden. Andernfalls führt der Main Thread Checker (neu eingeführte Debugging-Funktion in XCode 9) zur Laufzeit zu Problemen. Wickeln Sie Ihren Code also wie unten beschrieben in den Haupt-Thread-Block ein, um Störungen und Laufzeitwarnungen zu vermeiden.

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

In Xcode-Releases vor ver. In 9 werden die Warnungen in Bezug auf den Haupt-Thread im Konsolenbereich in Textform gedruckt. Auf jeden Fall können Sie den Haupt-Thread-Checker in den Diagnoseeinstellungen im Bearbeitungsschema optional deaktivieren ( kein empfohlener Ansatz ) .


Erläuterung:

Apple hat in XCode 9 eine neue Debugging-Option eingeführt, mit der Probleme bei Runtime for UIKit und anderen APIs, die Benutzeroberflächenelemente bearbeiten, überprüft werden können. Wenn zur Laufzeit Änderungen an den UI-Elementen von der UIKit-API ohne einen Hauptthreadblock vorgenommen werden, ist es sehr wahrscheinlich, dass UI-Störungen und Abstürze auftreten. Der Haupt-Thread-Checker ist standardmäßig aktiviert, um diese Probleme zur Laufzeit zu erkennen. Sie können die Haupt-Thread-Prüfung im Fenster " Schema bearbeiten" wie unten beschrieben deaktivieren , obwohl dies nicht unbedingt empfohlen wird:

Deaktivieren Sie die Haupt-Thread-Prüfung

Wenn Sie ältere SDKs oder Frameworks haben, wird beim Aktualisieren auf Xcode 9 möglicherweise diese Warnung angezeigt, da einige der UIKit-Methodenaufrufe nicht in den Hauptthread eingeschlossen worden wären. Das Aktualisieren auf die neueste Version würde das Problem beheben (wenn der Entwickler davon Kenntnis hat und es behoben hat).

Zitat aus den Beta-Versionshinweisen zu XCode 9:

  • Neu in Xcode 9 - Main Thread Checker.
    • Aktivieren Sie die Erkennung von UI-API-Missbrauch im Hintergrund-Thread
    • Erkennt AppKit-, UIKit- und WebKit-Methodenaufrufe, die nicht im Hauptthread ausgeführt werden.
    • Wird beim Debuggen automatisch aktiviert und kann auf der Registerkarte Diagnose des Schema-Editors deaktiviert werden.
    • Der Haupt-Thread-Checker funktioniert mit den Sprachen Swift und C.

1
Neugierig, wie haben Sie diese neuen Xcode 9-Einstellungen so schnell gelernt? Es gibt noch keine WWDC-Videos!
Honey

4
@Honey Die Versionshinweise enthalten normalerweise alle notwendigen Änderungen :)
Sulthan

4
@Honey Einige Leute lesen die Versionshinweise und die Dokumentation ;-)
Vadian

1
@Honey Im Ernst, es lohnt sich immer, die (Xcode) Versionshinweise zu lesen.
Vadian

2
@BadhanGanesh (ich habe weder herabgestimmt noch hochgestimmt) Wenn das nicht das ist, was Sie beabsichtigt haben, schreiben Sie es neu ... weil es so ist, als würde jemand sagen, ich habe Problem X ... und dann antworten Sie, Sie können Y tun ... nun, das OP sucht nach Antworten. Wenn es nur eine Erklärung ist, dann machen Sie klar, dass es keine Antwort ist
Honey

6

Die Fehlermeldung ist ziemlich klar: Versand registerForRemoteNotificationsan den Haupt-Thread.

Ich würde den grantedParameter verwenden und das errorentsprechend behandeln

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

3

Dies ist auch in Swift 4.0 der richtige Weg

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

1

Hoffe das wird helfen

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

1

Das hat bei mir funktioniert. Mit freundlicher Genehmigung von @ Mason11987 im oben akzeptierten Kommentar.

DispatchQueue.main.async() { code }
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.