Krijg je de foutmelding “Deze toepassing wijzigt de autolayout-engine vanuit een achtergrondthread”?

Ik ben deze fout vaak tegengekomen in mijn OS X met swift:

“Deze applicatie past de autolayout-engine aan vanuit een achtergrondthread, wat kan leiden tot engine-corruptie en vreemde crashes. Dit zal een uitzondering veroorzaken in een toekomstige release.”

Ik heb een my NSWindowen ik wissel van weergave naar de contentViewvan het venster. Ik krijg de foutwanneer ik probeer een NSApp.beginSheetin het venster te doen, of wanneer ik een subviewaan het venster toevoeg. Geprobeerd om dingen voor automatisch aanpassen uit te schakelen, en ik heb niets met automatische lay-out. Enig idee?

Soms gaat het goed en gebeurt er niets, andere keren verbreekt het mijn UIen laadt er niets


Antwoord 1, autoriteit 100%

Het moet in een andere thread worden geplaatst, zodat de gebruikersinterface kan worden bijgewerkt zodra de uitvoering van de threadfunctie is voltooid:

Moderne Swift:

DispatchQueue.main.async {
    // Update UI
}

Oudere versies van Swift, pre Swift 3.

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

Doelstelling-C:

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

Antwoord 2, autoriteit 23%

Je krijgt een gelijkaardige foutmelding terwijl je debugging met print statementszonder ‘dispatch_async’ te gebruiken
Dus als je die foutmelding krijgt, is het tijd om

. te gebruiken

Swift 4

DispatchQueue.main.async { //code }

Swift 3

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

Eerdere Swift-versies

dispatch_async(dispatch_get_main_queue()){ //code }

Antwoord 3, autoriteit 13%

De fout “deze toepassing wijzigt de autolayout-engine vanuit een achtergrondthread” wordt in de console vastgelegd lang nadat het daadwerkelijke probleem zich voordeed, dus het kan moeilijk zijn om dit op te lossen zonder een onderbrekingspunt te gebruiken.

Ik heb het antwoord van @markussvensson gebruikt om mijn probleem op te sporen en heb het gevonden met behulp van dit Symbolic Breakpoint(Debug > Breakpoints > Create Symbolic Breakpoint):

  1. Symbolen: [UIView layoutIfNeeded]of [UIView updateConstraintsIfNeeded]
  2. Voorwaarde: !(BOOL)[NSThread isMainThread]

voer hier de afbeeldingsbeschrijving in

Bouw de app en voer deze uit op de emulator en repliceer de stappen die ertoe hebben geleid dat de foutmelding wordt gegenereerd (de app zal langzamer zijn dan normaal!). Xcode stopt dan de app en markeert de coderegel (bijvoorbeeld de aanroep van een func) die toegang heeft tot de gebruikersinterface vanuit een achtergrondthread.


Antwoord 4, autoriteit 4%

Als u een tekstveldwaarde probeert bij te werken of een subview toevoegt in een achtergrondthread, kunt u dit probleem krijgen. Om die reden moet je dit soort code in de hoofdthread plaatsen.

Je moet methoden die UI-updates aanroepen met dispatch_asynch inpakken om de hoofdwachtrij te krijgen. Bijvoorbeeld:

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

BEWERKT – SWIFT 3:

Nu kunnen we dat doen door de volgende code te volgen:

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

Antwoord 5, autoriteit 3%

Voor mij was deze foutmelding afkomstig van een banner van Admob SDK.

Ik heb de oorsprong kunnen traceren naar “WebThread” door een voorwaardelijk breekpunt in te stellen.

voorwaardelijk breekpunt om te vinden wie ui bijwerkt vanuit de achtergrondthread

Toen kon ik het probleem oplossen door de bannercreatie in te kapselen met:

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

Ik weet niet waarom dit heeft geholpen, want ik kan niet zien hoe deze code werd aangeroepen vanuit een niet-main-thread.

Ik hoop dat het iemand kan helpen.


Antwoord 6, autoriteit 3%

Ik had dit probleem sinds het updaten naar de iOS 9 SDK toen ik een blok aanriep dat UI-updates deed binnen een NSURLConnection asynchrone afhandelingshandler voor verzoeken. Het plaatsen van de blokkering in een dispatch_async met behulp van dispatch_main_queue loste het probleem op.

Het werkte prima in iOS 8.


Antwoord 7, autoriteit 2%

Ik had hetzelfde probleem omdat ik performSelectorInBackgroundgebruikte.


Antwoord 8

Het belangrijkste probleem met “Deze toepassing wijzigt de autolayout-engine vanuit een achtergrondthread” is dat het lang nadat het daadwerkelijke probleem is opgetreden, lijkt te worden geregistreerd, dit kan het erg moeilijk maken om het probleem op te lossen.

Ik heb het probleem kunnen oplossen door drie symbolische breekpunten te creëren.

Foutopsporing > Breekpunten > Creëer symbolisch breekpunt…

Breekpunt 1:

  • Symbool: -[UIView setNeedsLayout]

  • Voorwaarde: !(BOOL)[NSThread isMainThread]

Breekpunt 2:

  • Symbool: -[UIView layoutIfNeeded]

  • Voorwaarde: !(BOOL)[NSThread isMainThread]

Breekpunt 3:

  • Symbool: -[UIView updateConstraintsIfNeeded]

  • Voorwaarde: !(BOOL)[NSThread isMainThread]

Met deze breekpunten kun je gemakkelijk een pauze krijgen op de eigenlijke regel waar je UI-methoden op niet-hoofdthread onjuist aanroept.


Antwoord 9

U mag de gebruikersinterface niet buiten de hoofdthread wijzigen! UIKit is niet thread-safe, dus dat bovenstaande probleem en ook enkele andere rare problemen zullen optreden als je dat doet. De app kan zelfs crashen.

Dus, om de UIKit-bewerkingen uit te voeren, moet u een blok definiëren en laten uitvoeren op de hoofdwachtrij: zoals,

NSOperationQueue.mainQueue().addOperationWithBlock {
}

Antwoord 10

Het is duidelijk dat u een UI-update uitvoert op de achtergrond. Kan niet precies voorspellen waar, zonder je code te zien.

Dit zijn enkele situaties waarin het kan gebeuren:-

misschien doet u iets in de achtergrondthread en gebruikt u dit niet. Omdat deze code dezelfde functie heeft, is deze gemakkelijker te herkennen.

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

aanroepen van een func-doing web request-aanroep op achtergrondthread en de voltooiingshandler die andere func-doing ui-update aanroept.
om dit op te lossen, probeert u de code te controleren waar u de gebruikersinterface hebt bijgewerkt na een webverzoek.

// 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()
            }
}

Antwoord 11

Ik had dit probleem tijdens het herladen van gegevens in UITableView. Door simpelweg het herladen als volgt te verzenden, werd het probleem voor mij opgelost.

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

12

U hebt al het juiste code antwoord van @mark, maar om mijn bevindingen te delen:
Het probleem is dat u een wijziging in de weergave vraagt ​​en ervan uitgaande dat het onmiddellijk zal gebeuren. In werkelijkheid hangt het laden van een weergave af van de beschikbare bronnen. Als alles snel genoeg laadt en er geen vertragingen zijn, merk je dan niets. In scenario’s, waar een vertraging is als gevolg van het proces van de procesdraad bezet, werkt de toepassing in een situatie waarin het zou moeten worden weergegeven, hoewel het nog niet klaar is. Daarom is het raadzaam om deze verzoeken in een asynchrone wachtrijen te verzenden, dus worden ze uitgevoerd op basis van de belasting.


13

Ik had dit probleem toen ik Touchid gebruikte als dat iemand anders helpt, je succeslogica wikkelt die waarschijnlijk iets met de UI in de hoofdwachtrij doet.


14

Het kan zo eenvoudig zijn als het instellen van een tekstveld / labelwaarde of het toevoegen van een subview in een achtergronddraad, die de lay-out van een veld kan veroorzaken om te veranderen. Zorg ervoor dat alles wat u met de interface alleen in de hoofddraad gebeurt.

Controleer deze link: https://forums.developer.apple.com/thread/7399


15

Als u op deze fout wilt jagen, gebruikt u het selectievakje Hoofddiscussie van de hoofddraadcontrole op problemen.
Fixing It is meestal eenvoudig, die de problematische lijn in de hoofdwachtrij wordt verzonden.

 Voer hier de afbeeldingsomschrijving in


Antwoord 16

Ik kwam dit probleem ook tegen, toen ik zag dat een heleboel van deze berichten en stapelsporen in de uitvoer werden afgedrukt, toen ik het formaat van het venster verkleinde tot een kleiner formaat dan de oorspronkelijke waarde. Ik besteedde veel tijd aan het uitzoeken van het probleem, en dacht dat ik de vrij eenvoudige oplossing zou delen. Ik had ooit Can Draw Concurrentlyingeschakeld op een NSTextViewvia IB. Dat vertelt AppKit dat het de draw(_:)-methode van de view vanuit een andere thread kan aanroepen. Na het uitschakelen kreeg ik geen foutmeldingen meer. Ik ondervond geen problemen voordat ik update naar macOS 10.14 Beta, maar tegelijkertijd begon ik ook de code aan te passen om werk met de tekstweergave uit te voeren.

Other episodes