UIApplication.registerForRemoteNotifications () se debe llamar solo desde el hilo principal

81

Xcode 9 (iOS 11) me muestra un error / advertencia al registrarme para la notificación Push (remota).

Aquí hay un mensaje de error

ingrese la descripción de la imagen aquí

Y aquí está el código, lo intenté:

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

Línea de error / advertencia:

UIApplication.shared.registerForRemoteNotifications ()

¿Cómo resolver esto?

Krunal
fuente
2
Como se dice en el mensaje de error, debe ajustar la llamada a UIApplication.shared.registerForRemoteNotifications()en el hilo principal. :) Vamos a google cómo llamarlo en el hilo principal ...
Duyen-Hoa
@Hoa, ¿por qué necesitarías hacer esto desde mainThread? No está relacionado con la interfaz de usuario ... ¿o es porque tiene el potencial de suceder unos segundos más tarde y eso podría causar un comportamiento inesperado?
Honey
También tengo la misma confusión, por qué Swift 4 me muestra este indicador de error ...
Krunal
@Sulthan The UIApplication.shared.registerForRemoteNotifications()no está relacionado con la interfaz de usuario (no avisa a los usuarios cuando obtiene el token para notificaciones silenciosas). Entonces, la línea que muestra el error es confusa. Sin embargo, registrarse para las insignias, alertas y sonidos está relacionado con la interfaz de usuario y es mucho mejor hacerlo desde el hilo principal ... así que, en general, todo el bloque center.requestAuthorization(options:...debe hacerse desde el hilo principal ... tiene sentido
Cariño,
Tuve un problema que extiende esto que se puede encontrar aquí . Tenía el mensaje de error abordado en esta pregunta, así como en otras.
joshLor

Respuestas:

141

En swift4

Puede resolver este problema con

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

Espero que esto ayude ...

Wasim K. Memon
fuente
Aún más simple, no hay necesidad de cerrar:DispatchQueue.main.async(execute: UIApplication.shared.registerForRemoteNotifications())
nathan
@nathan creo que necesitas el cierre. Recibí un Cannot invoke 'async' with an argument list of type '(execute: Void)'error al usar tu ejemplo.
bvpb
4
Lo sentimos, error tipográfico: DispatchQueue.main.async(execute: UIApplication.shared.registerForRemoteNotifications). executeespera una función / cierre de tipo, () -> Voidasí que registerForRemoteNotificationsfunciona
nathan
1
cómo escribir en el objetivo c.
Pooja Srivastava
5
@PoojaSrivastavadispatch_async(dispatch_get_main_queue(), ^{ //Do stuff });
badhanganesh
45

Para Objective C, el siguiente código funciona

    dispatch_async(dispatch_get_main_queue(), ^{
        [[UIApplication sharedApplication] registerForRemoteNotifications];
    });
R. Mohan
fuente
36

TL; DR:
Todas las manipulaciones de la interfaz de usuario deben realizarse en el hilo principal para evitar problemas. Si no lo hizo, Main Thread Checker (función de depuración recién introducida en XCode 9) producirá problemas en tiempo de ejecución. Así que envuelva su código en el bloque Main Thread como se muestra a continuación para evitar fallas y advertencias de tiempo de ejecución.

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

En versiones de Xcode anteriores a la ver. 9, las advertencias relacionadas con el hilo principal se imprimirían textualmente en el área de la consola. De todos modos, puede deshabilitar opcionalmente ( no es un enfoque recomendado ) el Comprobador de subprocesos principal en la configuración de diagnóstico en Editar esquema .


Explicación:

Apple introdujo una nueva opción de depuración en XCode 9 para verificar problemas en Runtime para UIKit y otras API que manipulan elementos de UI. Si hay algún cambio en los elementos de la interfaz de usuario de la API de UIKit en tiempo de ejecución, sin un bloque de hilo principal, es muy probable que cause fallas y fallas en la interfaz de usuario. El Comprobador de subprocesos principal está habilitado de forma predeterminada para detectar esos problemas en tiempo de ejecución. Puede deshabilitar el Comprobador de subprocesos principal en la ventana Editar esquema como se muestra a continuación, aunque realmente no se recomienda hacerlo:

Desactivar el verificador de hilo principal

Si tiene algún SDK o Frameworks más antiguo, al actualizar a Xcode 9, puede enfrentar esta advertencia ya que algunas de las llamadas al método UIKit no se habrían envuelto en Main Thread. Actualizarlos a la última versión solucionaría el problema (si el desarrollador lo sabe y lo soluciona).

Cita de las notas de la versión beta de XCode 9:

  • Nuevo en Xcode 9 - Main Thread Checker.
    • Habilitar la detección del uso indebido de la API de la interfaz de usuario desde el hilo en segundo plano
    • Detecta llamadas a métodos AppKit, UIKit y WebKit que no se realizan en el hilo principal.
    • Se habilita automáticamente durante la depuración y se puede deshabilitar en la pestaña Diagnóstico del editor de esquemas.
    • Main Thread Checker funciona con los lenguajes Swift y C.
badhanganesh
fuente
1
¿Tienes curiosidad por saber cómo aprendiste esta nueva configuración de Xcode 9 tan rápido? ¡Aún no hay videos de la WWDC!
Honey
4
@Honey Las notas de la versión generalmente contienen todos los cambios necesarios :)
Sulthan
4
@Honey Algunas personas leen las notas de la versión y la documentación ;-)
vadian
1
@Honey En serio, siempre vale la pena leer las notas de la versión de (Xcode).
vadian
2
@BadhanGanesh (no voté en contra ni a favor) si eso no es lo que pretendías, entonces reescribe ... porque es como si alguien dijera que tengo un problema X ... y luego tú respondes que puedes hacer Y ... bueno, el OP está buscando respuestas. Si es solo una explicación, deja en claro que no es una respuesta
Cariño
6

El mensaje de error es bastante claro: despacho registerForRemoteNotifications al hilo principal.

Usaría el grantedparámetro y manejaría el en errorconsecuencia

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

Esta también es la forma correcta de hacerlo en Swift 4.0

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

Espero que esto ayude

DispatchQueue.main.async(execute: {
  UIApplication.shared.registerForRemoteNotifications()
})
Basir Alam
fuente
1

Esto es lo que funcionó para mí. Cortesía de @ Mason11987 en el comentario aceptado arriba.

DispatchQueue.main.async() { code }
Gibraltar
fuente