“Bu uygulama otomatik yerleşim motorunu bir arka plan iş parçacığından değiştiriyor” hatası mı alıyorsunuz?


310

Swift kullanarak OS X'imde bu hatayla çok fazla karşılaşıyorum:

"Bu uygulama, motorun bozulmasına ve garip çökmelere neden olabilecek bir arka plan iş parçacığından otomatik yerleşim motorunu değiştiriyor. Bu, gelecekteki bir sürümde bir istisnaya neden olacaktır."

Benim bir NSWindow var ve contentViewpencerenin görünümlerinde takas ediyorum . Elde hatayı ben çalıştığınızda ve bir yapmak NSApp.beginSheetpencere, yoksa bir eklerken subviewpencereye. Otomatik boyutlandırma öğelerini devre dışı bırakmayı denedim ve otomatik düzeni kullanan hiçbir şeyim yok. Düşüncesi olan var mı?

Bazen iyi ve hiçbir şey olmuyor, bazen de tamamen kırılıyor UIve hiçbir şey yüklenmiyor


2
Nedense aşağıda mükemmel bir cevap silindi: github.com/nrbrook/NBUIKitMainThreadGuard
Fattie

En azından birkaç saatimi kurtardım. Teşekkürler @Fattie
oyalhi

sağ @oyalhi. kullanırken dikkatli olun, gerçekten zevk aldım ama sonra başka sorunları da vardı - zor bir alan! Umarım yardımcı olur!
Fattie

Bir yarı İlgili soru
Bal

Yanıtlar:


638

İş parçacığı işlevinin yürütülmesi tamamlanır tamamlanmaz kullanıcı arabiriminin güncellenmesini sağlayan farklı bir iş parçacığının içine yerleştirilmesi gerekir:

Modern Swift:

DispatchQueue.main.async {
    // Update UI
}

Eski sürümleri Swift, Pre Swift 3.

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

Objective-C:

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

3
Bunun Amaç C'de çalışması için, kod bloğundaki {ve önüne noktalı virgül sonra da ^ (void) koyun.
avance

4
Acımasa da, sadece ^ yerine ^ (void) gerekli değildir. Cevabın Objective-C versiyonu gayet iyi.
Keller

2
Benim için iyi çalışıyor. Benim sorunum için, bir ağ isteği yapmak ve başarı tamamlama bloğu içinde kullanıcı arayüzünü güncellemek için işlev çağırdı. UIKit iş parçacığı için güvenli olmadığından, kullanıcı arayüzünü güncellemek için ana iş parçacığına geri göndermeniz gerekir.
Rachel

1
Swift 3 çözümü için @Naishta tarafından verilen cevaba bakınız
Nathaniel

1
Swift 3 için: @Naishta'nın dediği gibi DispatchQueue.main.async () { code }
smukamuka

146

Yazdırma ifadeleriyle 'dispatch_async' kullanmadan hata ayıklarken benzer hata iletisi alıyorsunuz. Bu hata iletisini aldığınızda, kullanma zamanı

Hızlı 4

DispatchQueue.main.async { //code }

Hızlı 3

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

Önceki Swift sürümleri

dispatch_async(dispatch_get_main_queue()){ //code }

5
sözdizimi yanlış olduğundan, olmalıdır: dispatch_async(dispatch_get_main_queue(), ^{ /* UI related code */ });Düzenleme: Ben cevabını güncelledim, sözdizimi biçimlendirme orada daha iyi çalışır.
Zoltán

1
veya bir kapatma içerisindeyken, bunu kullanarak arka plan iş parçacığından ana dizeye inin: self.performSelectorOnMainThread (Seçici ("yourFunction:"), withObject: 'yourArray / yourObject', waitUntilDone: true)
Naishta

1
Hayır, sözdizimine bir göz atın
Naishta

82

"Bu uygulama bir arka plan iş parçacığından otomatik yerleşim motoru değiştiriyor" hatası, gerçek sorun oluştuktan uzun süre sonra konsolda günlüğe kaydedilir, bu nedenle bu hata ayıklama bir kesme noktası kullanmadan zor olabilir.

Sorunumu tespit etmek için @ markussvensson'un cevabını kullandım ve bu Sembolik Kesme Noktasını (Hata Ayıklama> Kesme Noktaları> Sembolik Kesme Noktası Oluştur) kullanarak buldum :

  1. Semboller: [UIView layoutIfNeeded]veya[UIView updateConstraintsIfNeeded]
  2. Durum: !(BOOL)[NSThread isMainThread]

resim açıklamasını buraya girin

Emülatörde uygulamayı oluşturun ve çalıştırın ve atılan hata mesajına yol açan adımları çoğaltın (uygulama normalden daha yavaş olacaktır!). Xcode daha sonra uygulamayı durdurur ve arka plan iş parçacığından kullanıcı arayüzüne erişen kod satırını (örn. Bir fonk çağrısı) işaretler.


3
Hmm. Bunu iptal ettim, çünkü mantıklı görünüyordu. Ancak, yürütme kesilmez ve yine de günlüklerimdeki hatayı alıyorum. Sembolik bir kırılma noktası ayarlamak için kullanabileceğim başka koşullar var mı?
Sjakelien

Benim durumumda kırılıyor. Ancak yığın izlemesi bana hangi görüşün sorumlu olduğuna dair herhangi bir ipucu vermez. Gösterilen montajcı kodunu nasıl yorumlayacağımı bilmiyorummovq 0x10880ba(%rip), %rsi ; "_wantsReapplicationOfAutoLayoutWithLayoutDirtyOnEntry:"
Reinhard Männer

Hata ayıklama sırasında uygulamanın yavaş çalışmasına neden olmaz mı?
Itachi

@Itachi yep. Nasıl hızlanacağını bilmiyorum.
k06a

2
Xcode 9 ile başlayarak yerleşik bir özelliktir. Şema ayarlarının "Tanı" sekmesinde "Ana Konu Denetleyicisi" seçeneğinin etkinleştirildiğinden emin olun
AndrewPo

24

Bir metin alanı değerini güncellemeye veya bir arka plan iş parçacığının içine bir alt görünüm eklemeye çalıştığınızda, bu sorunu alabilirsiniz. Bu nedenle, bu tür kodu ana iş parçacığına koymalısınız.

Ana kuyruğu almak için UI güncellemelerini çağıran yöntemleri dispatch_asynch ile sarmanız gerekir. Örneğin:

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

DÜZENLENMİŞ - SWIFT 3:

Şimdi, bunu bir sonraki kodu izleyerek yapabiliriz:

// 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

Benim için bu hata iletisi, Admob SDK'dan bir banner'dan kaynaklandı.

Koşullu bir kesme noktası ayarlayarak "WebThread" kaynağını izleyebildim.

arka plan iş parçacığından kullanıcı arabirimini kimin güncellediğini bulmak için koşullu kesme noktası

Sonra Banner oluşturma ile kapsülleyerek bu sorundan kurtulabildim:

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

Bu kod ana olmayan bir iş parçacığından nasıl çağrıldığını göremiyorum neden bu yardımcı oldu bilmiyorum.

Umarım herkese yardımcı olabilir.


1
Ben de aynı problemi yaşadım. Bir WebThread'de istisnanın neden oluştuğuna şaşırdım. Seninle aynı değişikliği yaptım ve şimdi çalışıyor. Admob sdk'nin biraz eski bir sürümünü kullanıyorum. Son sürümde düzeltilip düzeltilmediğini merak ediyorum. Bunun için teşekkürler. Onu bulacağımı sanmıyorum.
Larry

1
AdMob'un en son sürümüne güncelleme, bu sorunu benim için çözdü
JH95

Bunun gibi sembolik bir kesme noktasında bir mola alıyorum, ancak kod gösterilmiyor. :(
Victor Engel

20

NSURLConnection zaman uyumsuz istek tamamlama işleyicisi içinde UI güncellemeleri yapan bir blok çağırırken iOS 9 SDK'ya güncelleme yaptığımdan beri bu sorunu yaşadım. Dispatch_main_queue kullanarak blok çağrısını bir dispatch_async içine koymak sorunu çözdü.

İOS 8'de iyi çalıştı.


10

Aynı sorunu vardı çünkü kullanıyordum performSelectorInBackground.


Hayır, arka planda bir şeyler yapmam gerekiyordu. NSNotificationCenter çağrısını dispatch_async (dispatch_get_main_queue () yöntemi içine koydum ve işe yaradı.
Bobby

Daha sonra bir NSNotification bir UIViewController bildirime yanıt verdi bir URLSessionDelegate veri alıyordum ve orada veri iyi olup olmadığını kullanıcıya göstermek için DispatchQueue.main.async kullandım. Yanlış! - Çözüm Bildirimi ana kuyruğa alır. DispatchQueue.main.async {NotificationCenter.default.post (ad: NSNotification.Name (rawValue: networkNotificationNames.products.rawValue), nesne: self, userInfo: [networkNotificationNames.products.rawValue: productList])}
iCyberPaul

7

Ana iş parçacığının dışındaki kullanıcı arayüzünü değiştirmemelisiniz! UIKit iş parçacığı güvenli değildir, bu nedenle yukarıdaki sorun ve ayrıca bazı garip sorunlar ortaya çıkar. Uygulama çökebilir.

Bu nedenle, UIKit işlemlerini yapmak için, bloğu tanımlamanız ve ana kuyrukta yürütülmesine izin vermeniz gerekir: örneğin,

NSOperationQueue.mainQueue().addOperationWithBlock {

}

Bu, Xcode 7.2 ve iOS 9.2'de mevcut değildir. Başka alternatif var mı?
Jayprakash Dubey

7

Açıkçası arka zemin iş parçacığında UI güncellemesi yapıyorsunuz. Kodunuzu görmeden tam olarak nerede olduğunu tahmin edemem.

Bunlar meydana gelebilecek bazı durumlar: -

arka plan iş parçacığında bir şeyler yapıyor ve kullanmıyor olabilirsiniz. Aynı işlevde olan bu kodun tespit edilmesi daha kolaydır.

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

arka plan iş parçacığında web isteği çağrısı ve tamamlama işleyicisi çağıran başka bir çağrıyı yapan başka bir çağırma çağrısı yapıyor. Bu sorunu çözmek için, web isteğinde bulunduktan sonra kullanıcı arayüzünü güncellediğiniz kodu kontrol etmeyi deneyin.

// 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

"Bu uygulama bir arka plan iş parçacığından autolayout motoru değiştiriyor" ile ana sorun, gerçek sorun oluştuktan sonra uzun süre günlüğe kaydedilmiş gibi görünüyor, bu sorun gidermeyi çok zorlaştırabilir.

Üç sembolik kırılma noktası oluşturarak sorunu çözmeyi başardım.

Hata ayıklama> Kesme noktaları> Sembolik Kesme Noktası Oluştur ...

Kesme noktası 1:

  • sembol: -[UIView setNeedsLayout]

  • Durum: !(BOOL)[NSThread isMainThread]

Kesme noktası 2:

  • sembol: -[UIView layoutIfNeeded]

  • Durum: !(BOOL)[NSThread isMainThread]

Kesme noktası 3:

  • sembol: -[UIView updateConstraintsIfNeeded]

  • Durum: !(BOOL)[NSThread isMainThread]

Bu kesme noktaları ile, ana olmayan iş parçacığında UI yöntemlerini yanlış çağırdığınız gerçek satırda kolayca bir mola alabilirsiniz.


4

UITableView veri yeniden yüklerken bu sorunu vardı. Sadece aşağıdaki gibi yeniden yüklemeyi göndermek benim için sorunu çözdü.

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

Bu benim içindi! Ana kuyrukta başka bir şey vardı ama başıboş bir reloadData ()!
Oprimus

3

Ben de aynı problemi yaşadım. I dışarı Dönüşler kullanıyordum UIAlertsana kuyruk ihtiyacı olduğunu. Ancak, kullanımdan kaldırıldı .
Ben değiştiğinde UIAlertsiçin UIAlertController, artık sorun vardı ve herhangi kullanmak yoktu dispatch_asynckodu. Ders - uyarılara dikkat edin. Beklemediğiniz zamanlarda bile yardımcı olurlar.


3

@Mark'tan doğru kod cevabına zaten sahipsiniz, ancak sadece bulgularımı paylaşmak için: Sorun, görünümde bir değişiklik talep etmeniz ve anında gerçekleşeceğini varsaymanızdır. Gerçekte, bir görünümün yüklenmesi mevcut kaynaklara bağlıdır. Her şey yeterince hızlı yüklenirse ve gecikme yoksa hiçbir şey fark etmezsiniz. İşlem iş parçacığı vb. Nedeniyle herhangi bir gecikme olduğu senaryolarda, uygulama henüz hazır olmasa bile bir şey görüntülemesi gereken bir duruma girer. Bu nedenle, bu istekleri yüke bağlı olarak yürütülmeleri için eşzamansız kuyruklarda göndermeniz önerilir.


2

Bu sorun, başkalarına yardımcı olursa TouchID kullanırken, büyük olasılıkla ana kuyruktaki kullanıcı arayüzüyle bir şeyler yapan başarı mantığınızı sarın.


2

Bir metin alanı / etiket değeri ayarlamak veya bir arka plan iş parçacığının içine bir alt görünüm eklemek kadar basit olabilir, bu da bir alanın düzeninin değişmesine neden olabilir. Arabirimle yaptığınız her şeyin yalnızca ana iş parçacığında gerçekleştiğinden emin olun.

Bu bağlantıyı kontrol edin: https://forums.developer.apple.com/thread/7399


2

Aynı ViewController içinde UILabel hata mesajını güncellemeye çalışırken aynı sorunu vardı (normal kodlama ile yapmaya çalışırken verileri güncellemek için biraz zaman alır). Ben kullanılan DispatchQueueSwift 3 Xcode 8'de ve çalışıyor.


2

Bu hatayı avlamak istiyorsanız, sorunlarda ana iş parçacığı denetleyicisi duraklatması onay kutusunu kullanın. Bunu düzeltmek çoğu zaman kolaydır ve sorunlu hattı ana kuyrukta gönderir.

resim açıklamasını buraya girin


1
Bu tam olarak ne yapıyor? "Ana iş parçacığı denetleyicisi" varsayılan olarak etkinleştirildi ve ben de her ikisi için de "iş parçacığı temizleyici" ve "sorunları üzerinde duraklatma" kontrol etti, ancak yine de daha fazla bilgi eklemeden "arka plan iş parçacığında değişiklik" iletisini atar.
Nefis

Uygulamanın, arka plan iş parçacığında kullanıcı arayüzünün değiştirildiği noktada yürütülmesini duraklatır.
rockdaswift

Tuhaf, bunu uygulamamda yapmadı (Xcode 10.2.1). Ben duraklama ve kod satırında beni işaret almak için ( burada açıklandığı gibi ) kesme noktaları eklemek zorunda kaldı .
Nefis

Ve bu seçenekleri görmek için ne yapmalıyım?
David Rector


1

Benim için sorun şuydu. performSegueWithIdentifier:Ana iplikte yapıldığından emin olun :

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

1

Swift 4,

İşlem kuyruğunu kullanarak bir yöntem çağırıyorsanız,

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

Ve diyelim ki fonksiyon searchFavourites,

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

çağırırsanız, ana iş parçacığında "searchFavourites" yöntemi içindeki tüm kod, içinde bazı kullanıcı arabirimi güncelleştiriyorsanız yine de bir hata verecektir.

Bu uygulama, motora ana iplikten erişildikten sonra otomatik yerleşim motorunu bir arka plan iş parçacığından değiştirir.

Bu yüzden çözüm kullanın,

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

Bu tür bir senaryo için.


1

İşte bu satırı günlüklerden kontrol edin

$S12AppName18ViewControllerC11Func()ySS_S2StF + 4420

arka plan iş parçacığından hangi işlevi çağıracağınızı veya api yöntemini çağırdığınızı hangi işlevin böyle ana iş parçacığından çağırmanız gerektiğini kontrol edebilirsiniz.

DispatchQueue.main.async { func()}

func (), api çağrı başarılı veya başka bir sonuçta çağırmak istediğiniz işlevdir.

Burada Günlükleri

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

Pencereyi başlangıç ​​değerinden daha küçük bir boyuta yeniden boyutlandırdığımda, bu mesajların ve yığın izlerinin bir tonunun çıktıda yazdırıldığını görerek de bu sorunla karşılaştım. Sorunu çözmek için uzun zaman geçirdim, oldukça basit bir çözümü paylaşacağımı düşündüm. Bir keresinde Can Draw Concurrentlybir NSTextViewIB üzerinden etkinleştirmiştim . Bu, AppKit'e görünümün draw(_:)yöntemini başka bir iş parçacığından çağırabileceğini bildirir . Devre dışı bıraktıktan sonra artık herhangi bir hata mesajı almadım. MacOS 10.14 Beta sürümüne güncellemeden önce herhangi bir sorunla karşılaşmadım, ancak aynı zamanda metin görünümü ile çalışma yapmak için kodu değiştirmeye başladım.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.