UIApplication.registerForRemoteNotifications() must be called from main thread only

41,866

Solution 1

In swift4

You can solve this issue with

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

Hope this will help...

Solution 2

For Objective C, the below code works

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

Solution 3

TL;DR:
All UI manipulations should be done in the Main Thread to avoid problems. If failed to do so, Main Thread Checker (Newly introduced debugging feature in Xcode 9) will produce issues at Runtime. So wrap your code in Main Thread block like below to avoid glitches and runtime warnings.

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

In Xcode releases before ver. 9, the warnings related to main thread would get printed in the console area textually. Anyway, you can optionally disable (not a recommended approach) the Main Thread Checker in the Diagnostic settings in Edit Scheme.

Explanation:

Apple introduced a new debugging option in Xcode 9 for checking issues at Runtime for UIKit and other API's that manipulate UI elements. If there's any change to the UI elements from UIKit API at Runtime, without a Main thread block, it is highly likely to cause UI glitches and crashes. The Main Thread Checker is enabled by default to catch those issues at runtime. You can disable Main Thread Checker in the Edit Scheme window just like below, although it is not really recommended to do so:

Disable Main Thread Checker

If you have any older SDK's or Frameworks, when updating to Xcode 9, you may face this warning since some of the UIKit method calls wouldn't have been wrapped in Main Thread. Updating them to latest version would fix the issue (if the developer is aware of it and fixed it).

Quote from Xcode 9 beta release notes:

  • New in Xcode 9 – Main Thread Checker.
  • **Enable detection of UI API

misuse from background thread**

  • Detects AppKit, UIKit, and WebKit method calls that are not made on the main thread.
  • Automatically enabled during debugging, and can be disabled in the Diagnostic tab of the scheme editor.
  • Main Thread Checker works with Swift and C languages.

Solution 4

The error message is pretty clear: dispatch registerForRemoteNotifications to the main thread.

I would use the granted parameter and handle the error accordingly

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

Solution 5

In swift 4 or 5

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

on Objectiv-C

dispatch_async(dispatch_get_main_queue(), ^{
        [[UIApplication sharedApplication] registerForRemoteNotifications];
});
Share:
41,866

Related videos on Youtube

Krunal
Author by

Krunal

Contact me, if you're looking for a CTO or Engineering Director/VP. contact: +91 - 9737007007 mail: [email protected] Following some great SO users....

Updated on April 10, 2021

Comments

  • Krunal
    Krunal about 3 years

    Xcode 9 (iOS 11) showing me an error/warning while registering for Push (remote) notification.

    Here is error message

    enter image description here

    And here is code, I've tried:

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

    Error/Warning Line:

    UIApplication.shared.registerForRemoteNotifications()

    How to resolve this?

    • Duyen-Hoa
      Duyen-Hoa about 7 years
      As said in the error message, you have to wrap the call to UIApplication.shared.registerForRemoteNotifications() in the main thread. :) Let google how to call it in main thread ...
    • mfaani
      mfaani about 7 years
      @Hoa why would you need to do this from mainThread? It's not UI related...or is it because it has the potential to happen a few seconds later and that could cause unexpected behavior?
    • Krunal
      Krunal about 7 years
      I also have same confusion, why Swift 4 is showing me this error indicator...
    • mfaani
      mfaani about 7 years
      @Sulthan The UIApplication.shared.registerForRemoteNotifications() isn't UI related (you don't prompt users when you get token for silent Notifications). So the line the error is showing is confusing. However registering for the badges, alerts, sounds is UI related and it's much better to do it from main thread...so overall the entire block of center.requestAuthorization(options:... must be done from main thread...it makes sense
    • joshLor
      joshLor about 7 years
      I had a problem that extends this that can be found here. I had the error message addressed in this question as well as others.
  • mfaani
    mfaani about 7 years
    Curious how did you learn this Xcode 9 new settings so quick? There are no WWDC videos out yet!
  • Sulthan
    Sulthan about 7 years
    @Honey The release notes usually contain all the necessary changes :)
  • vadian
    vadian about 7 years
    @Honey Some people read the release notes and the documentation ;-)
  • mfaani
    mfaani about 7 years
    @vadian facepalm...I'm still a noob...this is actually the first time I able to catchup and follow up on a WWDC
  • vadian
    vadian about 7 years
    @Honey Seriously, it's always worth it to read the (Xcode) release notes.
  • cvb
    cvb about 7 years
    This thing is tripping on UIKit tasks done in a background context, which has nothing to do with the UI. Don't down vote this....it's good info.
  • mfaani
    mfaani about 7 years
    @BadhanGanesh (I didn't downvote nor upvoted) if that's not what you intended then rewrite it...because it's like someone saying I have problem X...and then you replying you can do Y....well the OP is looking for answers. If it's just an explanation than make it clear that it's not answer
  • nathan
    nathan almost 7 years
    Even simpler, there's no need for the closure: DispatchQueue.main.async(execute: UIApplication.shared.registerForRemoteNotifications())
  • Philip De Vries
    Philip De Vries almost 7 years
    Hmmmm so even traversing through the subviews is giving me this warning. I'm not trying to manipulate anything in the UI, just creating thumbs in the background. Should I really dispatch every line dealing with UIViews to the main thread?
  • badhanganesh
    badhanganesh almost 7 years
    @PhilipDeVries All UIKit method-calls should be in main thread. You are probably calling methods of UIKit in BG.
  • bvpb
    bvpb almost 7 years
    @nathan I think you need the closure. I got a Cannot invoke 'async' with an argument list of type '(execute: Void)' error using your example.
  • nathan
    nathan almost 7 years
    Sorry, typo: DispatchQueue.main.async(execute: UIApplication.shared.registerForRemoteNotifications). execute expects a function/closure of type () -> Void so registerForRemoteNotifications works
  • Pooja Srivastava
    Pooja Srivastava over 6 years
    how to write in objective c.
  • Ming Zhu
    Ming Zhu over 6 years
    Will this kind of warning/error be subject to AppStore rejection? I asked this because I have a really special usage of WKWebView in a background thread (acting as a Javascript engine, instead of JSCore, since the WebView has better JS performance with JIT compilation and JS execution)
  • badhanganesh
    badhanganesh over 6 years
    @PoojaSrivastava dispatch_async(dispatch_get_main_queue(), ^{ //Do stuff });
  • cristallo
    cristallo over 6 years
    I am pretty confused, even if I am using the DispatchQueue.main.async, the Main Thread Checker is still displaying the warning