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()主线程中。:)让Google如何在主线程中调用它
Duyen-Hoa

@Hoa为什么需要从mainThread进行此操作?这与UI无关...或者是因为它有可能在几秒钟后发生,并且可能导致意外行为?
亲爱的

我也有同样的困惑,为什么Swift 4会向我显示此错误指示器...
Krunal

@Sulthan这UIApplication.shared.registerForRemoteNotifications()与UI无关(当您获得静默通知的令牌时,您不会提示用户)。因此错误显示的令人困惑。但是,注册徽章,警报,声音是与UI相关的,最好从主线程进行操作...因此,总体而言,center.requestAuthorization(options:...必须从主线程完成整个操作...这是有道理的
Honey

我有一个问题可以扩展到这里。我在这个问题以及其他问题中都解决了错误消息。
joshLor17年

Answers:


141

swift4

您可以使用以下方法解决此问题

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

希望这会有所帮助...


更简单的是,无需关闭:DispatchQueue.main.async(execute: UIApplication.shared.registerForRemoteNotifications())
森(Nathan)

@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

45

对于目标C,以下代码适用

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

36

TL; DR:
所有UI操作都应在主线程中完成,以避免出现问题。如果这样做失败,则主线程检查器(XCode 9中新引入的调试功能)将在运行时产生问题。因此,将您的代码包装在主线程块中,如下所示,以避免出现故障和运行时警告。

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

在Xcode之前的版本中。在图9中,与主线程相关的警告将以文本形式打印在控制台区域中。无论如何,您可以选择在“编辑方案”的“诊断”设置中禁用(不是推荐的方法)主线程检查器。


说明:

Apple在XCode 9中引入了新的调试选项,用于在运行时检查UIKit和其他处理UI元素的API的问题。如果运行时UIKit API中的UI元素发生任何更改,而没有Main线程块,则很有可能导致UI故障和崩溃。默认情况下,“主线程检查器”处于启用状态,以便在运行时捕获这些问题。您可以在“编辑方案”窗口中禁用主线程检查器,如下所示,尽管实际上不建议这样做:

禁用主线程检查器

如果您有任何较旧的SDK或框架,则在更新到Xcode 9时,您可能会遇到此警告,因为某些UIKit方法调用不会包装在主线程中。将它们更新到最新版本将解决此问题(如果开发人员意识到并已解决)。

引用XCode 9 beta发行说明:

  • Xcode 9中的新功能–主线程检查器。
    • 启用从后台线程检测UI API滥用
    • 检测未在主线程上进行的AppKit,UIKit和WebKit方法调用。
    • 在调试过程中自动启用,并且可以在方案编辑器的“诊断”选项卡中禁用。
    • 主线程检查器可用于Swift和C语言。

1
好奇您如何快速学习Xcode 9的新设置?还没有WWDC视频!
蜂蜜

4
@Honey发布说明通常包含所有必要的更改:)
Sulthan

4
@Honey有些人阅读了发行说明和文档;-)
vadian

1
@Honey认真地说,阅读(Xcode)发行说明始终是值得的。
vadian

2
@BadhanGanesh(我既不反对也不反对),如果那不是您想要的,则将其重写...因为就像有人在说我有问题X ...然后您回答可以做Y ....正在寻找答案。如果只是解释而不是明确表示没有答案
亲爱的

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 }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.