UIApplication.registerForRemoteNotifications() необходимо вызывать только из основного потока

Xcode 9 (iOS 11), показывающий мне ошибку/предупреждение при регистрации для Push (удаленного) уведомления.

Вот сообщение об ошибке

enter image description here

И вот код, я пробовал:

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()

Как это решить?

Ответ 1

В swift4

Вы можете решить эту проблему с помощью

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

Надеюсь, это поможет...

Ответ 2

Для цели C приведенный ниже код работает

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

Ответ 3

TL; DR:
Все манипуляции с пользовательским интерфейсом должны выполняться в главной теме, чтобы избежать проблем. Если этого не сделать, Main Thread Checker (недавно введенная функция отладки в XCode 9) вызовет проблемы во время выполнения. Поэтому оберните свой код в блоке Main Thread, как показано ниже, чтобы избежать сбоев и предупреждений во время выполнения.

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

В версиях Xcode перед версией. 9, предупреждения, связанные с основным потоком, будут печататься в текстовой области консоли. Во всяком случае, вы можете опционально отключить (не рекомендуемый подход) Main Thread Checker в настройках диагностики в Edit Scheme.


Объяснение:

Apple представила новую опцию для отладки в XCode 9 для проверки проблем в Runtime для UIKit и другого API, которые управляют элементами пользовательского интерфейса. Если какие-либо изменения элементов UI из UIKit API в Runtime без блока Main thread, это, скорее всего, вызовет сбои пользовательского интерфейса и сбои. По умолчанию функция Main Thread Checker включена, чтобы уловить эти проблемы во время выполнения. Вы можете отключить Main Thread Checker в окне Edit Scheme, как показано ниже, хотя на самом деле это не рекомендуется:

Disable Main Thread Checker

Если у вас есть старые SDK или Framework, при обновлении до Xcode 9 вы можете столкнуться с этим предупреждением, так как некоторые вызовы метода UIKit не были бы завернуты в главный поток. Обновление их до последней версии устранит проблему (если разработчик знает об этом и исправил ее).

Цитата из примечаний к выпуску XCode 9:

  • Новое в Xcode 9 - Main Thread Checker.
    • Включить обнаружение неправильного использования API-интерфейса API из фонового потока
    • Обнаруживает вызовы метода AppKit, UIKit и WebKit, которые не выполняются в основном потоке.
    • Автоматически включается во время отладки и может быть отключена на вкладке "Диагностика" редактора схем.
    • Main Thread Checker работает с языками Swift и C.

Ответ 4

Сообщение об ошибке довольно ясно: отправьте 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
        }
}

Ответ 5

Это также правильный способ сделать 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()
                }
            }
        })

Ответ 6

Надеюсь, это поможет

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

Ответ 7

Это то, что сработало для меня. Предоставлено @Mason11987 в принятом комментарии выше.

DispatchQueue.main.async() { code }