Bắt một ứng dụng này Ứng dụng này đang sửa đổi công cụ tự động thanh toán từ một lỗi nền chủ đề?


310

Đã gặp phải lỗi này rất nhiều trong OS X của tôi khi sử dụng swift:

"Ứng dụng này đang sửa đổi công cụ tự động thanh toán từ một luồng nền, điều này có thể dẫn đến hỏng động cơ và các sự cố kỳ lạ. Điều này sẽ gây ra ngoại lệ trong phiên bản tương lai."

Tôi có một con chó săn của tôi và tôi đang tráo đổi tầm nhìn ra contentViewcửa sổ. Tôi gặp lỗi khi tôi thử và thực hiện NSApp.beginSheettrên cửa sổ hoặc khi tôi thêm một subviewvào cửa sổ. Đã thử vô hiệu hóa nội dung tự động hóa và tôi không có bất cứ điều gì khi sử dụng bố cục tự động. Có suy nghĩ gì không?

Đôi khi nó ổn và không có gì xảy ra, lần khác nó hoàn toàn phá vỡ tôi UIvà không có gì tải


2
Vì một số lý do, một câu trả lời xuất sắc dưới đây đã bị xóa: github.com/nrbrook/NBUIKitMainThreadGuard
Fattie

Tiết kiệm cho tôi ít nhất vài giờ. Cảm ơn @Fattie
idhihi

đúng @idelhi. Hãy cẩn thận khi sử dụng nó, tôi thực sự rất thích nó nhưng sau đó cũng có những vấn đề khác - đó là một lĩnh vực khó khăn! hy vọng nó giúp!
Fattie

một câu hỏi bán liên quan
Mật ong

Câu trả lời:


638

Nó cần được đặt bên trong một luồng khác cho phép UI cập nhật ngay khi thực hiện chức năng luồng hoàn thành:

Swift hiện đại:

DispatchQueue.main.async {
    // Update UI
}

Các phiên bản cũ hơn của Swift, trước Swift 3.

dispatch_async(dispatch_get_main_queue(){
    // code here
})

Mục tiêu-C:

dispatch_async(dispatch_get_main_queue(), ^{
    // code here
});

3
Để làm cho công việc này trong Mục tiêu C, đặt ^ (void) trước {trong khối mã và một dấu chấm phẩy.
avance 27/8/2015

4
Mặc dù nó không bị tổn thương, ^ (void) thay vì chỉ ^ là không cần thiết. Phiên bản Objective-C của câu trả lời là tốt.
Keller

2
Việc này ổn với tôi. Đối với vấn đề của tôi là, thực hiện một yêu cầu mạng và bên trong khối hoàn thành thành công tôi đã gọi hàm để cập nhật giao diện người dùng. Vì UIKit không phải là luồng an toàn, nên cần gửi trở lại luồng chính để cập nhật giao diện người dùng.
Rachel

1
Xem câu trả lời của @Naishta cho giải pháp Swift 3
Nathaniel

1
Đối với Swift 3: DispatchQueue.main.async () { code }, như @Naishta đã nói
smukamuka

146

Bạn nhận được thông báo lỗi tương tự trong khi gỡ lỗi với các câu lệnh in mà không sử dụng 'Clark_async' Vì vậy, khi bạn nhận được thông báo lỗi đó, đã đến lúc sử dụng

Swift 4

DispatchQueue.main.async { //code }

Swift 3

DispatchQueue.main.async(){ //code }

Các phiên bản Swift trước đó

dispatch_async(dispatch_get_main_queue()){ //code }

5
bởi vì cú pháp sai, nên: dispatch_async(dispatch_get_main_queue(), ^{ /* UI related code */ });Chỉnh sửa: Tôi đã cập nhật câu trả lời của anh ấy, định dạng cú pháp hoạt động tốt hơn ở đó.
Zoltán

1
hoặc, khi bên trong một đóng cửa, xuống xe đến mainthread từ thread nền sử dụng này: self.performSelectorOnMainThread (Selector ( "yourFunction:"), withObject: 'yourArray / yourObject', waitUntilDone: true)
Naishta

1
Không, không, hãy xem cú pháp
Naishta

82

Lỗi "ứng dụng này đang sửa đổi công cụ tự động thoát khỏi luồng nền" được ghi lại trong bảng điều khiển rất lâu sau khi xảy ra sự cố thực tế, do đó, việc gỡ lỗi này có thể khó khăn mà không sử dụng điểm dừng.

Tôi đã sử dụng câu trả lời của @ markussvensson để phát hiện vấn đề của mình và tìm thấy nó bằng cách sử dụng Điểm dừng tượng trưng này (Gỡ lỗi> Điểm dừng> Tạo Điểm dừng biểu tượng):

  1. Biểu tượng: [UIView layoutIfNeeded]hoặc[UIView updateConstraintsIfNeeded]
  2. Tình trạng: !(BOOL)[NSThread isMainThread]

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

Xây dựng và chạy ứng dụng trên trình giả lập và sao chép các bước dẫn đến thông báo lỗi bị ném (ứng dụng sẽ chậm hơn bình thường!). Xcode sau đó sẽ dừng ứng dụng và đánh dấu dòng mã (ví dụ: lệnh gọi của func) đang truy cập UI từ một luồng nền.


3
Hừm. Tôi ủng hộ điều này, bởi vì nó dường như có ý nghĩa. Tuy nhiên, việc thực thi không bị phá vỡ và tôi vẫn nhận được lỗi trong nhật ký của mình. Có điều kiện nào khác tôi có thể sử dụng để đặt điểm dừng tượng trưng không?
Sjakelien

Trong trường hợp của tôi, nó không phá vỡ. Tuy nhiên, theo dõi ngăn xếp không cho tôi bất kỳ gợi ý nào xem có trách nhiệm. Và tôi không biết làm thế nào để diễn giải mã trình biên dịch được hiển thịmovq 0x10880ba(%rip), %rsi ; "_wantsReapplicationOfAutoLayoutWithLayoutDirtyOnEntry:"
Reinhard Männer

Nó có khiến ứng dụng chạy chậm nghiêm trọng khi gỡ lỗi không?
Itachi

@Itachi vâng. Không biết làm thế nào để tăng tốc.
k06a

2
Bắt đầu với Xcode 9, đây là một tính năng tích hợp. Chỉ cần đảm bảo tùy chọn "Trình kiểm tra chủ đề chính" được bật trong tab "Chẩn đoán" trong cài đặt
Lược đồ

24

Khi bạn cố cập nhật giá trị trường văn bản hoặc thêm một khung nhìn phụ bên trong một luồng nền, bạn có thể gặp vấn đề này. Vì lý do đó, bạn nên đặt loại mã này trong luồng chính.

Bạn cần phải bọc các phương thức gọi cập nhật giao diện người dùng bằng Clark_asynch để có được hàng đợi chính. Ví dụ:

dispatch_async(dispatch_get_main_queue(), { () -> Void in
   self.friendLabel.text = "You are following \(friendCount) accounts"
})

EDITED - CHUYỂN 3:

Bây giờ, chúng ta có thể làm điều đó theo mã tiếp theo:

// Move to a background thread to do some long running work
DispatchQueue.global(qos: .userInitiated).async {
   // Do long running task here
   // Bounce back to the main thread to update the UI
   DispatchQueue.main.async {
      self.friendLabel.text = "You are following \(friendCount) accounts"
   }
}

23

Đối với tôi, thông báo lỗi này bắt nguồn từ một biểu ngữ từ SDK SDK.

Tôi đã có thể theo dõi nguồn gốc thành "WebThread" bằng cách đặt điểm dừng có điều kiện.

điểm dừng có điều kiện để tìm ai đang cập nhật ui từ luồng nền

Sau đó, tôi đã có thể thoát khỏi vấn đề bằng cách gói gọn việc tạo Banner bằng:

dispatch_async(dispatch_get_main_queue(), ^{
   _bannerForTableFooter = [[GADBannerView alloc] initWithAdSize:kGADAdSizeSmartBannerPortrait];
   ...
}

Tôi không biết tại sao điều này lại hữu ích vì tôi không thể thấy mã này được gọi từ một luồng không chính.

Hy vọng nó có thể giúp bất cứ ai.


1
Tôi đã từng gặp vấn đề tương tự. Tôi đã bối rối tại sao ngoại lệ xảy ra trong một WebThread. Tôi đã thực hiện thay đổi tương tự như bạn đã làm và bây giờ nó hoạt động. Tôi đang sử dụng một phiên bản hơi lỗi thời của sdk admob. Tôi tự hỏi nếu nó đã được sửa trong phiên bản mới nhất. Cảm ơn vì điều đó. Tôi không nghĩ rằng tôi sẽ tìm thấy nó.
Larry

1
Cập nhật lên phiên bản mới nhất của AdMob đã giải quyết vấn đề này cho tôi
JH95

Tôi được nghỉ tại một điểm dừng tượng trưng như thế này, nhưng không được hiển thị mã. :(
Victor Engel

20

Tôi gặp vấn đề này kể từ khi cập nhật lên SDK iOS 9 khi tôi đang gọi một khối đã cập nhật giao diện người dùng trong trình xử lý hoàn thành yêu cầu đồng bộ hóa NSURLConnection. Việc thực hiện cuộc gọi chặn trong Clark_async bằng cách sử dụng Clark_main_queue đã giải quyết được vấn đề.

Nó hoạt động tốt trong iOS 8.


10

Có cùng một vấn đề bởi vì tôi đã sử dụng performSelectorInBackground.


Không, tôi cần phải làm những điều trong nền. Tôi đặt cuộc gọi NSNotificationCenter bên trong phương thức Clark_async (Clark_get_main_queue () và nó đã hoạt động.
Bobby

Tôi đã nhận được dữ liệu từ URLSessionDelegate, sau đó được gọi là NSNotification, UIViewControll đã trả lời thông báo và trong đó tôi đã sử dụng DispatchQueue.main.async để hiển thị cho người dùng xem dữ liệu có tốt hay không. Sai lầm! - Giải pháp là đưa Thông báo vào hàng đợi chính. DispatchQueue.main.async {NotificationCenter.default.post (tên: NSNotification.Name (rawValue: networkNotificationNames.products.rawValue), đối tượng: tự, UserInfo: [networkNotificationNames.products.rawValue: productList])}
iCyberPaul

7

Bạn không được thay đổi giao diện người dùng việt vị chủ đề chính! UIKit không phải là chủ đề an toàn, do đó, vấn đề trên và một số vấn đề kỳ lạ khác sẽ phát sinh nếu bạn làm điều đó. Ứng dụng thậm chí có thể bị sập.

Vì vậy, để thực hiện các thao tác UIKit, bạn cần xác định khối và để nó được thực thi trên hàng đợi chính: chẳng hạn như,

NSOperationQueue.mainQueue().addOperationWithBlock {

}

Điều này không có sẵn trong Xcode 7.2 và iOS 9.2. Bất kỳ thay thế khác?
Jayprakash Dubey

7

Rõ ràng là bạn đang thực hiện một số cập nhật giao diện người dùng trên chủ đề mặt đất. Không thể dự đoán chính xác nơi, mà không thấy mã của bạn.

Đây là một số tình huống có thể xảy ra: -

bạn có thể đang làm gì đó trên luồng nền và không sử dụng. Ở cùng chức năng, mã này dễ phát hiện hơn.

DispatchQueue.main.async { // do UI update here }

gọi một func đang thực hiện yêu cầu web gọi trên luồng nền và trình xử lý hoàn thành của nó gọi func khác đang cập nhật ui. để giải quyết vấn đề này, hãy thử kiểm tra mã nơi bạn đã cập nhật giao diện người dùng sau cuộc gọi webrequest.

// Do something on background thread
DispatchQueue.global(qos: .userInitiated).async {
   // update UI on main thread
   DispatchQueue.main.async {
                // Updating whole table view
                self.myTableview.reloadData()
            }
}

5

Vấn đề chính với "Ứng dụng này đang sửa đổi công cụ tự động xóa khỏi luồng nền" là nó dường như được ghi lại một thời gian dài sau khi sự cố thực sự xảy ra, điều này có thể khiến việc khắc phục sự cố rất khó khăn.

Tôi quản lý để giải quyết vấn đề bằng cách tạo ra ba điểm dừng tượng trưng.

Gỡ lỗi> Điểm dừng> Tạo Điểm dừng tượng trưng ...

Điểm dừng 1:

  • Biểu tượng: -[UIView setNeedsLayout]

  • Tình trạng: !(BOOL)[NSThread isMainThread]

Điểm dừng 2:

  • Biểu tượng: -[UIView layoutIfNeeded]

  • Tình trạng: !(BOOL)[NSThread isMainThread]

Điểm dừng 3:

  • Biểu tượng: -[UIView updateConstraintsIfNeeded]

  • Tình trạng: !(BOOL)[NSThread isMainThread]

Với các điểm dừng này, bạn có thể dễ dàng ngắt dòng trên đường dây thực tế nơi bạn gọi không chính xác các phương thức UI trên luồng không chính.


4

Tôi gặp vấn đề này trong khi tải lại dữ liệu trong UITableView. Đơn giản chỉ cần gửi tải lại như sau đã khắc phục vấn đề cho tôi.

    dispatch_async(dispatch_get_main_queue(), { () -> Void in
        self.tableView.reloadData()
    })

Đây là nó cho tôi! Tôi đã có mọi thứ khác trên hàng đợi chính nhưng một reloadData () đi lạc!
Oprimus

3

Tôi đã từng gặp vấn đề tương tự. Hóa ra tôi đang sử dụng UIAlertscần hàng đợi chính. Nhưng, họ đã bị phản đối .
Khi tôi thay đổi UIAlertsđến UIAlertController, tôi không còn có vấn đề và không cần phải sử dụng bất kỳ dispatch_asyncmã. Bài học - chú ý đến các cảnh báo. Họ giúp đỡ ngay cả khi bạn không mong đợi nó.


3

Bạn đã có câu trả lời mã chính xác từ @Mark nhưng, chỉ để chia sẻ phát hiện của tôi: Vấn đề là bạn đang yêu cầu thay đổi quan điểm và cho rằng điều đó sẽ xảy ra ngay lập tức. Trong thực tế, việc tải một khung nhìn phụ thuộc vào các tài nguyên có sẵn. Nếu mọi thứ tải đủ nhanh và không có sự chậm trễ thì bạn không nhận thấy bất cứ điều gì. Trong các trường hợp, khi có bất kỳ độ trễ nào do luồng xử lý đang bận, v.v., ứng dụng sẽ gặp phải tình huống hiển thị nội dung nào đó mặc dù chưa sẵn sàng. Do đó, nên gửi các yêu cầu này trong một hàng đợi không đồng bộ để chúng được thực hiện dựa trên tải.


2

Tôi gặp vấn đề này khi tôi đang sử dụng TouchID nếu điều đó giúp được bất kỳ ai khác, bao bọc logic thành công của bạn có khả năng thực hiện điều gì đó với giao diện người dùng trong hàng đợi chính.


2

Nó có thể đơn giản như cài đặt giá trị trường / nhãn văn bản hoặc thêm một khung nhìn phụ bên trong một luồng nền, điều này có thể khiến bố cục của trường thay đổi. Hãy chắc chắn rằng bất cứ điều gì bạn làm với giao diện chỉ xảy ra trong luồng chính.

Kiểm tra liên kết này: https://forums.developer.apple.com/thread/7399


2

Tôi gặp vấn đề tương tự khi cố gắng cập nhật thông báo lỗi trong UILabel trong cùng ViewContoder (phải mất một chút thời gian để cập nhật dữ liệu khi cố gắng làm điều đó với mã hóa thông thường). Tôi đã sử dụng DispatchQueuetrong Swift 3 Xcode 8 và nó hoạt động.


2

Nếu bạn muốn tìm lỗi này, hãy sử dụng tạm dừng trình kiểm tra luồng chính trên hộp kiểm sự cố. Sửa chữa nó là dễ dàng hầu hết các lần, gửi dòng có vấn đề trong hàng đợi chính.

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


1
Điều này chính xác làm gì? "Trình kiểm tra luồng chính" được bật theo mặc định và tôi cũng đã kiểm tra thêm "Trình vệ sinh luồng" và "Tạm dừng các sự cố" cho cả hai nhưng nó vẫn chỉ ném thông báo "sửa đổi từ luồng nền" mà không thêm bất kỳ thông tin nào vào đó.
Neph

Nó tạm dừng việc thực thi ứng dụng tại điểm mà UI đang được sửa đổi trong một luồng nền.
rockdaswift

Thật kỳ lạ, nó đã không làm điều đó trong ứng dụng của tôi (Xcode 10.2.1). Tôi đã phải thêm các điểm dừng theo cách thủ công (như được mô tả ở đây ) để khiến nó tạm dừng và chỉ cho tôi dòng mã.
Cháu

Và tôi phải làm gì để thấy bộ tùy chọn này?
David Hiệu trưởng

Chỉnh sửa sơ đồ của mục tiêu của bạn
rockdaswift

1

Đối với tôi vấn đề là như sau. Đảm bảo performSegueWithIdentifier:được thực hiện trên luồng chính:

dispatch_async (dispatch_get_main_queue(), ^{
  [self performSegueWithIdentifier:@"ViewController" sender:nil];
});

1

Swift 4,

Giả sử, nếu bạn đang gọi một số phương thức bằng cách sử dụng hàng đợi hoạt động

operationQueue.addOperation({
            self.searchFavourites()
        })

Và giả sử chức năng searchFavourites giống như,

func searchFavourites() {
     DispatchQueue.main.async {
                    //Your code
                }
}

nếu bạn gọi, tất cả mã bên trong phương thức "searchFavourites" trên luồng chính, nó vẫn sẽ báo lỗi nếu bạn đang cập nhật một số UI trong đó.

Ứng dụng này đang sửa đổi công cụ tự động thanh toán từ một luồng nền sau khi công cụ được truy cập từ luồng chính.

Vì vậy, sử dụng giải pháp,

operationQueue.addOperation({
            DispatchQueue.main.async {
                self.searchFavourites()
            }
        })

Đối với loại kịch bản này.


1

Ở đây kiểm tra dòng này từ các bản ghi

$S12AppName18ViewControllerC11Func()ySS_S2StF + 4420

bạn có thể kiểm tra xem hàm nào gọi từ luồng nền hoặc nơi bạn đang gọi phương thức api, bạn cần gọi hàm của mình từ luồng chính như thế này.

DispatchQueue.main.async { func()}

func () là hàm mà bạn muốn gọi trong kết quả của cuộc gọi api thành công hay cách khác.

Đăng nhập tại đây

This application is modifying the autolayout engine from a background thread after the engine was accessed from the main thread. This can lead to engine corruption and weird crashes.
 Stack:(
    0   Foundation                          0x00000001c570ce50 <redacted> + 96
    1   Foundation                          0x00000001c5501868 <redacted> + 32
    2   Foundation                          0x00000001c5544370 <redacted> + 540
    3   Foundation                          0x00000001c5543840 <redacted> + 396
    4   Foundation                          0x00000001c554358c <redacted> + 272
    5   Foundation                          0x00000001c5542e10 <redacted> + 264
    6   UIKitCore                           0x00000001f20d62e4 <redacted> + 488
    7   UIKitCore                           0x00000001f20d67b0 <redacted> + 36
    8   UIKitCore                           0x00000001f20d6eb0 <redacted> + 84
    9   Foundation                          0x00000001c571d124 <redacted> + 76
    10  Foundation                          0x00000001c54ff30c <redacted> + 108
    11  Foundation                          0x00000001c54fe304 <redacted> + 328
    12  UIKitCore                           0x00000001f151dc0c <redacted> + 156
    13  UIKitCore                           0x00000001f151e0c0 <redacted> + 152
    14  UIKitCore                           0x00000001f1514834 <redacted> + 868
    15  UIKitCore                           0x00000001f1518760 <redacted> + 104
    16  UIKitCore                           0x00000001f1543370 <redacted> + 1772
    17  UIKitCore                           0x00000001f1546598 <redacted> + 120
    18  UIKitCore                           0x00000001f14fc850 <redacted> + 1452
    19  UIKitCore                           0x00000001f168f318 <redacted> + 196
    20  UIKitCore                           0x00000001f168d330 <redacted> + 144
    21  AppName                        0x0000000100b8ed00 $S12AppName18ViewControllerC11Func()ySS_S2StF + 4420
    22  AppName                        0x0000000100b8d9f4 $S12CcfU0_y10Foundation4DataVSg_So13NSURLResponseCSgs5Error_pSgtcfU_ + 2384
    23  App NAme                        0x0000000100a98f3c $S10Foundation4DataVSgSo13NSURLResponseCSgs5Error_pSgIegggg_So6NSDataCSgAGSo7NSErrorCSgIeyByyy_TR + 316
    24  CFNetwork                           0x00000001c513aa00 <redacted> + 32
    25  CFNetwork                           0x00000001c514f1a0 <redacted> + 176
    26  Foundation                          0x00000001c55ed8bc <redacted> + 16
    27  Foundation                          0x00000001c54f5ab8 <redacted> + 72
    28  Foundation                          0x00000001c54f4f8c <redacted> + 740
    29  Foundation                          0x00000001c55ef790 <redacted> + 272
    30  libdispatch.dylib                   0x000000010286f824 _dispatch_call_block_and_release + 24
    31  libdispatch.dylib                   0x0000000102870dc8 _dispatch_client_callout + 16
    32  libdispatch.dylib                   0x00000001028741c4 _dispatch_continuation_pop + 528
    33  libdispatch.dylib                   0x0000000102873604 _dispatch_async_redirect_invoke + 632
    34  libdispatch.dylib                   0x00000001028821dc _dispatch_root_queue_drain + 376
    35  libdispatch.dylib                   0x0000000102882bc8 _dispatch_worker_thread2 + 156
    36  libsystem_pthread.dylib             0x00000001c477917c _pthread_wqthread + 472
    37  libsystem_pthread.dylib             0x00000001c477bcec start_wqthread + 4
)

0

Tôi cũng gặp phải vấn đề này, thấy một tấn các thông báo và dấu vết ngăn xếp này được in ở đầu ra, khi tôi thay đổi kích thước cửa sổ thành kích thước nhỏ hơn giá trị ban đầu. Dành một thời gian dài để tìm ra vấn đề, tôi nghĩ tôi sẽ chia sẻ giải pháp khá đơn giản. Tôi đã từng được kích hoạt Can Draw Concurrentlytrên một NSTextViewqua IB. Điều đó nói với AppKit rằng nó có thể gọi draw(_:)phương thức của khung nhìn từ một luồng khác. Sau khi vô hiệu hóa nó, tôi không còn nhận được bất kỳ thông báo lỗi. Tôi không gặp phải bất kỳ sự cố nào trước khi cập nhật lên macOS 10.14 Beta, nhưng đồng thời, tôi cũng bắt đầu sửa đổi mã để thực hiện công việc với chế độ xem văn bản.

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.