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()이 메인 스레드에서에 대한 호출을 래핑해야합니다 . :) 메인 스레드를 호출하는 방법을 구글하자 ...
두옌 - 호아

@ Hoa 왜 mainThread에서 이것을해야합니까? UI와 관련이 없습니다 ... 아니면 몇 초 후에 발생할 가능성이있어 예상치 못한 동작이 발생할 수 있기 때문입니까?
Honey

나는 또한 ... 스위프트 (4)는 나에게이 오류 표시기를 보여주는 왜 같은 혼란을 가지고
Krunal

@Sulthan The UIApplication.shared.registerForRemoteNotifications()는 UI와 관련이 없습니다 (자동 알림에 대한 토큰을받을 때 사용자에게 메시지를 표시하지 않음). 따라서 오류가 표시 되는 은 혼란 스럽습니다. 그러나 배지, 경고, 사운드 등록은 UI와 관련이 있으며 메인 스레드에서하는 것이 훨씬 낫습니다. 전체 블록은 center.requestAuthorization(options:...메인 스레드에서 수행해야합니다 ... 그것은 의미가 있습니다
Honey

나는 여기 에서 찾을 수있는 이것을 확장하는 문제가 있었다 . 이 질문과 다른 질문에서 오류 메시지가 해결되었습니다.
joshLor

답변:


143

에서 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

46

Objective C의 경우 아래 코드가 작동합니다.

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

37

요약 :
모든 UI 조작은 문제를 방지하기 위해 메인 스레드에서 수행되어야합니다. 그렇게하지 않으면 메인 스레드 검사기 (XCode 9에서 새로 도입 된 디버깅 기능)가 런타임에 문제를 생성합니다. 따라서 결함과 런타임 경고를 피하기 위해 아래와 같이 Main Thread 블록에 코드를 래핑하십시오.

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

버전 이전의 Xcode 릴리스에서. 9에서는 메인 스레드와 관련된 경고가 콘솔 영역에 텍스트로 인쇄됩니다. 어쨌든 Edit SchemeDiagnostic 설정에서 Main Thread Checker를 선택적으로 비활성화 ( 권장되지 않는 방법 ) 할 수 있습니다 .


설명:

Apple은 UIKit 및 UI 요소를 조작하는 기타 API에 대한 런타임에서 문제를 확인하기 위해 XCode 9에 새로운 디버깅 옵션을 도입했습니다. 주 스레드 블록없이 런타임에 UIKit API에서 UI 요소가 변경되면 UI 결함 및 충돌이 발생할 가능성이 높습니다. 주 스레드 검사기는 런타임에 이러한 문제를 잡기 위해 기본적으로 활성화되어 있습니다. 실제로 권장하지는 않지만 아래와 같이 Edit Scheme 창 에서 Main Thread Checker 를 비활성화 할 수 있습니다 .

주 스레드 검사기 비활성화

이전 SDK 또는 프레임 워크가있는 경우 Xcode 9로 업데이트 할 때 일부 UIKit 메서드 호출이 Main Thread에서 래핑되지 않았으므로이 경고가 표시 될 수 있습니다. 최신 버전으로 업데이트하면 문제가 해결됩니다 (개발자가이를인지하고 수정 한 경우).

XCode 9 베타 릴리스 노트에서 인용 :

  • Xcode 9의 새로운 기능 – 메인 스레드 검사기.
    • 백그라운드 스레드에서 UI API 오용 감지 활성화
    • 주 스레드에서 수행되지 않은 AppKit, UIKit 및 WebKit 메서드 호출을 감지합니다.
    • 디버깅 중에 자동으로 활성화되며 체계 편집기의 진단 탭에서 비활성화 할 수 있습니다.
    • 메인 스레드 검사기는 Swift 및 C 언어에서 작동합니다.

1
이 Xcode 9 새로운 설정을 어떻게 그렇게 빨리 배웠는지 궁금하십니까? 아직 WWDC 동영상이 없습니다!
Honey

4
@Honey 릴리스 노트에는 일반적으로 필요한 모든 변경 사항이 포함되어 있습니다. :)
Sulthan

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 }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.