it-swarm.com.de

Abrufen des Fehlers "Diese Anwendung ändert die Autolayout-Engine von einem Hintergrund-Thread"

Dieser Fehler ist in meinem OS X mit Swift häufig aufgetreten: 

"Diese Anwendung modifiziert die Autolayout-Engine von einem Hintergrund-Thread aus, was zu einer Beschädigung der Engine und zu seltsamen Abstürzen führen kann. Dies führt in einer zukünftigen Version zu einer Ausnahme."

Ich habe mein NSWindow und wechsle die Ansichten auf die contentView des Fensters. Ich bekomme den Fehler , wenn ich versuche, einen NSApp.beginSheet im Fenster auszuführen oder wenn ich eine subview zum Fenster hinzufüge. Ich habe Autoresize-Sachen deaktiviert und ich habe nichts mit dem automatischen Layout. Irgendwelche Gedanken?

Manchmal ist es in Ordnung und es passiert nichts, manchmal bricht es meine UI und nichts wird geladen

273
Mark

Okay - fand die Antwort. Es muss in einem anderen Thread platziert werden, der die Aktualisierung der Benutzeroberfläche ermöglicht, sobald die Ausführung der Thread-Funktion abgeschlossen ist:

Swift 3

 DispatchQueue.main.async {
    // Update UI
 }

Schnelle Version <3

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

Ziel-C-Version

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

Sie erhalten eine ähnliche Fehlermeldung beim Debuggen mit print-Anweisungen , ohne 'dispatch_async' .__ zu verwenden. Wenn Sie diese Fehlermeldung erhalten, ist es an der Zeit, sie zu verwenden 

Swift 4

DispatchQueue.main.async { //code }

Swift 3

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

Frühere Swift-Versionen

dispatch_async(dispatch_get_main_queue()){ //code }
141
Naishta

Die @markussvensson-Antwort wurde verwendet, um mein Problem zu erkennen. Es wurde mithilfe dieses Symbolischen Haltepunkts gefunden:

  1. Symbole: [UIView layoutIfNeeded] oder [UIView updateConstraintsIfNeeded]
  2. Bedingung: !(BOOL)[NSThread isMainThread]

 enter image description here

67
k06a

Wenn Sie versuchen, einen Textfeldwert zu aktualisieren oder eine Unteransicht in einem Hintergrundthread hinzuzufügen, kann dieses Problem auftreten. Aus diesem Grund sollten Sie diese Art von Code in den Haupt-Thread einfügen.

Sie müssen Methoden, die UI-Updates aufrufen, mit dispatch_asynch umschließen, um die Hauptwarteschlange abzurufen. Zum Beispiel:

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

EDITED - Swift 3:

Jetzt können wir das nach dem nächsten Code tun:

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

Diese Fehlermeldung stammt für mich aus einem Banner des Admob SDK. 

Ich konnte den Ursprung in "WebThread" verfolgen, indem ich einen bedingten Haltepunkt setzte.

 conditional breakpoint to find who is updating ui from background thread

Dann konnte ich das Problem loswerden, indem ich die Bannererstellung mit folgendem Code einkapselte:

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

Ich weiß nicht, warum dies geholfen hat, da ich nicht sehen kann, wie dieser Code von einem Nicht-Main-Thread aufgerufen wurde.

Ich hoffe es kann jedem helfen.

21
markussvensson

Ich hatte dieses Problem seit der Aktualisierung auf das iOS 9-SDK, als ich einen Block aufrief, der Aktualisierungen der Benutzeroberfläche innerhalb eines NSURLConnection-Abarbeitungshandlers für async-Anforderungen ausführte. Das Blockieren des Aufrufs in dispatch_async mit dispatch_main_queue löste das Problem.

Es hat gut funktioniert in iOS 8.

19
spongessuck

Hatte das gleiche Problem, weil ich performSelectorInBackground verwendete.

10
Bobby

Sie dürfen die Benutzeroberfläche nicht außerhalb des Hauptthreads ändern! UIKit ist nicht threadsicher, so dass obiges Problem und auch einige andere seltsame Probleme auftreten, wenn Sie dies tun. Die App kann sogar abstürzen.

Um die UIKit-Operationen auszuführen, müssen Sie einen Block definieren und ihn in der Hauptwarteschlange ausführen lassen:

NSOperationQueue.mainQueue().addOperationWithBlock {

}

Offensichtlich führen Sie einige UI-Updates für den Hintergrund-Thread durch. Kann nicht genau vorhersagen wo, ohne Ihren Code zu sehen.

Dies sind einige Situationen, in denen es passieren kann: -

sie könnten etwas im Hintergrund-Thread tun und nicht verwenden. Da dieser Code in der gleichen Funktion ist, ist er leichter zu erkennen.

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

aufruf eines Funktionsaufrufs für einen Funktionsaufruf im Hintergrundthread und dessen Beendigungsprozedur Aufruf eines anderen Funktionsaufrufs, der UI-Update ausführt ..

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

Ich hatte dieses Problem beim Neuladen von Daten in UITableView. Durch das Senden von Reload wie folgt wurde das Problem für mich behoben.

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

Ich hatte das gleiche Problem. Es stellte sich heraus, dass ich UIAlerts verwendete, das die Hauptwarteschlange benötigte. Aber sie wurden veraltet .
Als ich die UIAlerts in die UIAlertController geändert habe, hatte ich das Problem nicht mehr und musste keinen dispatch_async-Code verwenden. Die Lektion - achten Sie auf Warnungen. Sie helfen auch, wenn Sie es nicht erwarten.

3
epaus

Sie haben bereits die richtige Code-Antwort von @Mark, aber um meine Ergebnisse zu teilen: Das Problem ist, dass Sie eine Änderung der Ansicht anfordern und davon ausgehen, dass dies sofort geschehen wird. In der Realität hängt das Laden einer Ansicht von den verfügbaren Ressourcen ab. Wenn alles schnell genug geladen wird und es keine Verzögerungen gibt, bemerken Sie nichts. In Szenarien, in denen aufgrund des ausgelasteten Prozessthreads eine Verzögerung auftritt, führt die Anwendung zu einer Situation, in der sie etwas anzeigen soll, obwohl sie noch nicht bereit ist. Daher ist es ratsam, diese Anforderungen in asynchronen Warteschlangen abzusetzen, damit sie basierend auf der Last ausgeführt werden. 

3
Mukund Agarwal

Ich hatte das gleiche Problem, als ich versuchte, die Fehlermeldung in UILabel im selben ViewController zu aktualisieren (es dauert etwas, bis die Daten aktualisiert werden, wenn dies mit normaler Codierung versucht wird). Ich habe DispatchQueue in Swift 3 Xcode 8 verwendet und es funktioniert.

2
FN90

Ich hatte dieses Problem, als ich TouchID verwendet habe, wenn dies anderen hilft, Ihre Erfolgslogik einzuwickeln, was wahrscheinlich etwas mit der Benutzeroberfläche in der Hauptwarteschlange tut. 

2
Stuart P.

Dies kann so einfach sein wie das Festlegen eines Textfelds/Beschriftungswerts oder das Hinzufügen einer Unteransicht in einem Hintergrundthread, wodurch sich das Layout eines Felds ändern kann. Stellen Sie sicher, dass alles, was Sie mit der Schnittstelle tun, nur im Haupt-Thread geschieht.

Überprüfen Sie diesen Link: https://forums.developer.Apple.com/thread/7399

2
Kiran P Nair

Das Hauptproblem bei "Diese Anwendung ändert das Autolayout-Modul von einem Hintergrundthread aus" ist, dass es lange nach dem Auftreten des eigentlichen Problems protokolliert zu sein scheint. Dies kann die Problembehandlung sehr erschweren.

Ich habe es geschafft, das Problem zu lösen, indem ich drei symbolische Haltepunkte geschaffen habe.

Debug> Haltepunkte> Symbolischen Haltepunkt erstellen ...

Haltepunkt 1:

  • Symbol: -[UIView setNeedsLayout]

  • Bedingung: !(BOOL)[NSThread isMainThread]

Haltepunkt 2:

  • Symbol: -[UIView layoutIfNeeded]

  • Bedingung: !(BOOL)[NSThread isMainThread]

Haltepunkt 3:

  • Symbol: -[UIView updateConstraintsIfNeeded]

  • Bedingung: !(BOOL)[NSThread isMainThread]

Mit diesen Unterbrechungspunkten können Sie leicht eine Unterbrechung in der tatsächlichen Zeile erhalten, in der Sie UI-Methoden für Nicht-Hauptthread fälschlicherweise aufrufen.

1

Swift 4,

Angenommen, Sie rufen eine Methode mit der Operationswarteschlange auf

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

Angenommen, die Funktion searchFavourites ist wie

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

wenn Sie den gesamten Code innerhalb der Methode "searchFavourites" im Hauptthread aufrufen, wird immer noch ein Fehler ausgegeben, wenn Sie einige Benutzeroberflächen darin aktualisieren. 

Diese Anwendung ändert die Autolayout-Engine vor dem Hintergrund Thread, nachdem auf die Engine vom Haupt-Thread aus zugegriffen wurde.

Also Lösung verwenden,

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

Für diese Art von Szenario.

1
Pramod More

Für mich war das Problem das folgende . Stellen Sie sicher, dass performSegueWithIdentifier: für den Haupt-Thread ausgeführt wird:

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

Dieses Problem ist auch aufgetreten. Ich habe eine Menge dieser Meldungen und Stapelspuren in der Ausgabe gedruckt, als ich die Größe des Fensters auf eine kleinere Größe als den ursprünglichen Wert reduzierte. Ich verbrachte lange Zeit damit, das Problem herauszufinden, und ich dachte, ich würde die ziemlich einfache Lösung teilen. Ich hatte einmal Can Draw Concurrently auf einer NSTextView durch IB aktiviert. Dies teilt AppKit mit, dass es die draw(_:)-Methode der Ansicht von einem anderen Thread aus aufrufen kann. Nach dem Deaktivieren erhielt ich keine Fehlermeldungen mehr. Ich hatte vor dem Update auf macOS 10.14 Beta keine Probleme, aber gleichzeitig begann ich auch, den Code so zu ändern, dass er mit der Textansicht arbeitet.

0
Andreas

Wenn Sie diesen Fehler beheben möchten, aktivieren Sie das Kontrollkästchen Pause bei Problemen. Das Beheben ist meistens einfach und löst die problematische Zeile in der Hauptwarteschlange aus. 

 enter image description here

0
rockdaswift