UIApplication.registerForRemoteNotifications () потрібно викликати лише з основного потоку


81

Xcode 9 (iOS 11) показує мені помилку / попередження під час реєстрації для push (віддаленого) сповіщення.

Ось повідомлення про помилку

введіть тут опис зображення

І ось код, я спробував:

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()основного потоку. :) Нехай google, як це називати, в основній темі ...
Дуйен-Хоа,

@Hoa, навіщо вам це робити з mainThread? Це не пов’язано з користувальницьким інтерфейсом ... або це тому, що це може статися через кілька секунд, і це може спричинити несподівану поведінку?
Мед

У мене також така ж плутанина, чому Swift 4 показує мені цей індикатор помилки ...
Krunal

@Sulthan UIApplication.shared.registerForRemoteNotifications()Не пов'язаний з інтерфейсом користувача (ви не підказуєте користувачам, коли ви отримуєте маркер для безшумних сповіщень). Тож рядок, який показує помилка, заплутаний. Однак реєстрація для значків, попереджень, звуків пов'язана з користувацьким інтерфейсом, і набагато краще це робити з основного потоку ... тому загалом весь блок center.requestAuthorization(options:...повинен виконуватися з основного потоку ... це має сенс
Honey

У мене була проблема, яка поширює це, і яку можна знайти тут . Я мав повідомлення про помилку, розглянуте в цьому питанні, а також інші.
joshLor

Відповіді:


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

4
До жаль, помилка: DispatchQueue.main.async(execute: UIApplication.shared.registerForRemoteNotifications). executeочікує функції / закриття типу, що () -> Voidтак registerForRemoteNotificationsпрацює
Натан

1
як писати об’єктивно c.
Pooja Srivastava

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

46

Для Цілі C працює наступний код

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

37

TL; DR:
Усі маніпуляції з користувацьким інтерфейсом повинні виконуватися в Основній нитці, щоб уникнути проблем. Якщо цього не вдалося зробити, Main Thread Checker (нещодавно введена функція налагодження в XCode 9) видасть проблеми під час виконання. Тож оберніть свій код в блоці Main Thread, як показано нижче, щоб уникнути збоїв та попереджень про час роботи.

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

У версіях Xcode перед версією. 9, попередження, пов'язані з основним потоком, надрукуються в області консолі текстуально. У будь-якому випадку, ви можете за бажанням вимкнути ( не рекомендований підхід ) перевірку основної нитки в налаштуваннях діагностики в редагуванні схеми .


Пояснення:

Apple представила новий варіант налагодження в XCode 9 для перевірки проблем під час виконання для UIKit та інших API, які маніпулюють елементами інтерфейсу. Якщо якісь зміни в елементах користувацького інтерфейсу від API UIKit під час виконання, без блоку основного потоку, є великою ймовірністю викликати збої та збої в користувацькому інтерфейсі. Головна Thread Checker включена за замовчуванням , щоб зловити ці питання під час виконання. Ви можете вимкнути головну перевірку потоків у вікні Редагування схеми, як показано нижче, хоча насправді це робити не рекомендується:

Вимкніть перевірку основної нитки

Якщо у вас є якісь старіші SDK або фреймворки, під час оновлення до Xcode 9 ви можете зіткнутися з цим попередженням, оскільки деякі виклики методу UIKit не були б обгорнуті в основну нитку. Оновлення їх до останньої версії дозволить вирішити проблему (якщо розробник це знає та виправив).

Цитата з бета-версії XCode 9:

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

1
Цікаво, як ви так швидко вивчили ці нові налаштування Xcode 9? Відео WWDC ще немає!
Мед

4
@Honey Примітки до випуску зазвичай містять усі необхідні зміни :)
Султан,

4
@Honey Деякі люди читають примітки до випуску та документацію ;-)
vadian

1
@Honey Серйозно, завжди варто читати примітки до випуску (Xcode).
vadian

2
@BadhanGanesh (я не голосував і не голосував), якщо це не те, що ви мали намір, то перепишіть його ... тому що це як те, що хтось каже, що у мене проблема X ... і тоді ви відповідаєте, що можете зробити Y .... ну OP шукає відповіді. Якщо це просто пояснення, тоді чітко дайте зрозуміти, що це не відповідь
Мед

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

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

1

Сподіваюся, це допоможе

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

1

Це те, що мені вдалося. Надано @ Mason11987 у прийнятому коментарі вище.

DispatchQueue.main.async() { code }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.