UIApplication.registerForRemoteNotifications () chỉ phải được gọi từ luồng chính


81

Xcode 9 (iOS 11) hiển thị cho tôi lỗi / cảnh báo khi đăng ký thông báo Đẩy (từ xa).

Đây là thông báo lỗi

nhập mô tả hình ảnh ở đây

Và đây là mã, tôi đã thử:

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

Dòng Lỗi / Cảnh báo:

UIApplication.shared.registerForRemoteNotifications ()

Làm thế nào để giải quyết điều này?


2
Như đã nói trong thông báo lỗi, bạn phải kết thúc cuộc gọi đến UIApplication.shared.registerForRemoteNotifications()trong chuỗi chính. :) Để google cách gọi nó trong main thread ...
Duyên-Hoa

@Hoa tại sao bạn cần làm điều này từ mainThread? Nó không liên quan đến giao diện người dùng ... hay là vì nó có khả năng xảy ra một vài giây sau đó và điều đó có thể gây ra hành vi không mong muốn?
Honey

Tôi cũng có cùng một sự nhầm lẫn, tại sao Swift 4 được hiển thị cho tôi chỉ lỗi này ...
Krunal

@Sulthan UIApplication.shared.registerForRemoteNotifications()Không liên quan đến giao diện người dùng (bạn không nhắc người dùng khi nhận được mã thông báo cho Thông báo im lặng). Vì vậy, dòng lỗi đang hiển thị là khó hiểu. Tuy nhiên việc đăng ký cho phù hiệu, cảnh báo, âm thanh được UI liên quan và nó tốt hơn nhiều việc phải làm nó từ chủ đề chính ... vì vậy tổng thể toàn bộ khối center.requestAuthorization(options:...phải được thực hiện từ chủ đề chính ... nó làm cho tinh thần
Mật ong

Tôi đã có một vấn đề mở rộng điều này có thể được tìm thấy ở đây . Tôi đã có thông báo lỗi được giải quyết trong câu hỏi này cũng như các câu hỏi khác.
joshLor

Câu trả lời:


141

Trong nhanh chóng4

Bạn có thể giải quyết vấn đề này với

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

Hy vọng điều này sẽ giúp ...


Thậm chí đơn giản hơn, không cần cho việc đóng cửa:DispatchQueue.main.async(execute: UIApplication.shared.registerForRemoteNotifications())
nathan

@nathan Tôi nghĩ bạn cần đóng cửa. Tôi gặp Cannot invoke 'async' with an argument list of type '(execute: Void)'lỗi khi sử dụng ví dụ của bạn.
bvpb

4
Xin lỗi, typo: DispatchQueue.main.async(execute: UIApplication.shared.registerForRemoteNotifications). executehy vọng một hàm / đóng loại () -> Voidđể registerForRemoteNotificationslàm việc
nathan

1
cách viết trong khách quan c.
Pooja Srivastava

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

45

Đối với Mục tiêu C, đoạn mã dưới đây hoạt động

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

36

TL; DR:
Tất cả các thao tác giao diện người dùng nên được thực hiện trong Chủ đề chính để tránh sự cố. Nếu không làm được như vậy, Bộ kiểm tra luồng chính (Tính năng gỡ lỗi mới được giới thiệu trong XCode 9) sẽ tạo ra các sự cố khi Runtime. Vì vậy, bọc mã của bạn trong khối Chủ đề chính như bên dưới để tránh trục trặc và cảnh báo thời gian chạy.

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

Trong bản phát hành Xcode trước ver. 9, các cảnh báo liên quan đến luồng chính sẽ được in dưới dạng văn bản trong khu vực bàn điều khiển. Dù sao, bạn có thể tùy ý vô hiệu hóa ( không phải là cách tiếp cận được khuyến nghị ) Bộ kiểm tra luồng chính trong cài đặt Chẩn đoán trong Sơ đồ chỉnh sửa .


Giải trình:

Apple đã giới thiệu một tùy chọn gỡ lỗi mới trong XCode 9 để kiểm tra các vấn đề trong Runtime cho UIKit và các API khác thao tác các phần tử giao diện người dùng. Nếu có bất kỳ thay đổi nào đối với các phần tử giao diện người dùng từ API UIKit lúc Runtime mà không có khối Chủ đề chính, thì rất có thể gây ra trục trặc và lỗi giao diện người dùng. Trình kiểm tra luồng chính được bật theo mặc định để bắt các vấn đề đó trong thời gian chạy. Bạn có thể tắt Trình kiểm tra luồng chính trong cửa sổ Chỉnh sửa lược đồ giống như bên dưới, mặc dù không thực sự khuyến khích làm như vậy:

Tắt công cụ kiểm tra chủ đề chính

Nếu bạn có bất kỳ SDK hoặc Khung công tác cũ hơn nào, khi cập nhật lên Xcode 9, bạn có thể gặp phải cảnh báo này vì một số lệnh gọi phương thức UIKit sẽ không được bao bọc trong Chuỗi chính. Cập nhật chúng lên phiên bản mới nhất sẽ khắc phục được sự cố (nếu nhà phát triển biết về nó và đã khắc phục).

Trích dẫn từ ghi chú phát hành XCode 9 beta:

  • Tính năng mới trong Xcode 9 - Trình kiểm tra luồng chính.
    • Cho phép phát hiện lạm dụng API giao diện người dùng từ chuỗi nền
    • Phát hiện các lệnh gọi phương thức AppKit, UIKit và WebKit không được thực hiện trên chuỗi chính.
    • Tự động bật trong quá trình gỡ lỗi và có thể bị vô hiệu hóa trong tab Chẩn đoán của trình chỉnh sửa lược đồ.
    • Main Thread Checker hoạt động với ngôn ngữ Swift và C.

1
Tò mò làm thế nào bạn tìm hiểu cài đặt mới Xcode 9 này nhanh như vậy? Không có video WWDC nào ra mắt!
Honey

4
@Honey Các ghi chú phát hành thường chứa tất cả những thay đổi cần thiết :)
Sulthan

4
@Honey Một số người đọc ghi chú phát hành và tài liệu ;-)
vadian

1
@Honey Nghiêm túc mà nói, luôn đáng để đọc các ghi chú phát hành (Xcode).
vadian

2
@BadhanGanesh (Tôi không phản đối cũng không ủng hộ) nếu đó không phải là những gì bạn dự định thì hãy viết lại nó ... bởi vì nó giống như ai đó nói rằng tôi có vấn đề X ... và sau đó bạn trả lời bạn có thể làm Y .... tốt rồi OP đang tìm kiếm câu trả lời. Nếu nó chỉ là một lời giải thích hơn làm cho nó rõ ràng rằng nó không trả lời
Mật ong

6

Thông báo lỗi khá rõ ràng: gửi registerForRemoteNotificationsđến luồng chính.

Tôi sẽ sử dụng các grantedtham số và xử lý errorphù hợp

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

3

Đây cũng là cách làm đúng trong 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

Hy vọng điều này sẽ giúp

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

1

Đây là những gì làm việc cho tôi. Được phép của @ Mason11987 trong nhận xét được chấp nhận ở trên.

DispatchQueue.main.async() { code }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.