web-dev-qa-db-fra.com

Cette application modifie le moteur d'autolayout à partir d'un thread en arrière-plan, ce qui peut entraîner une corruption du moteur et des accidents étranges.

Je reçois ce journal dans la console lorsque j'exécute mon application dans son simulateur. Je n'ai pas vu cela dans iOS 8. Je ne sais pas trop ce qui cause cela. Quelqu'un at-il rencontré le même problème et si oui, comment a-t-il été résolu? ou y a-t-il de l'aide que quelqu'un puisse fournir à cet égard?

36
Shabarinath Pabba

Ne changez pas l'interface utilisateur à partir de rien d'autre que du fil principal. Bien que cela puisse sembler fonctionner sur certains systèmes d'exploitation ou périphériques et pas sur d'autres, cela rendra votre application instable et provoquera un crash imprévisible.

Si vous devez répondre à une notification qui peut se produire en arrière-plan, assurez-vous que UIKit invocation a lieu sur le thread principal .

Vous avez au moins ces 2 options:

Envoi asynchrone

Utilisez GCD(Grand Central Dispatch) si votre observateur peut être averti sur n’importe quel fil. Vous pouvez écouter et travailler à partir de n’importe quel thread et encapsuler les modifications de l’UI dans un dispatch_async:

dispatch_async(dispatch_get_main_queue()) {
    // Do UI stuff here
}

Quand utiliser GCD? Lorsque vous ne contrôlez pas qui envoie la notification. Cela peut être le système d'exploitation, un Cocoapod, des bibliothèques intégrées, etc. L'utilisation de GCD se réveillera à tout moment, à tout moment. Inconvénient: vous vous retrouvez à réorganiser le travail.


Écoutez sur le fil principal

De manière pratique, vous pouvez spécifier sur quel thread vous souhaitez que l'observateur soit averti, au moment de votre enregistrement pour les notifications, à l'aide du paramètre queue:

addObserverForName:@"notification"
    object:nil
    queue:[NSOperationQueue mainQueue]
    usingBlock:^(NSNotification *note){
        // Do UI stuff here
    }

Quand observer sur le fil principal? Lorsque vous vous inscrivez et que vous vous inscrivez. Dès que vous répondez à la notification, vous êtes déjà là où vous devez être.


Publier une notification sur le fil principal

[self performSelectorOnMainThread:@selector(postNotification:) withObject:notification waitUntilDone:NO];

Solution hybride qui ne garantit pas que l’observateur n’est appelé que de cette méthode. Cela permet d'avoir un observateur plus léger, au prix d'une conception moins robuste. Seulement mentionné ici comme solution vous devriez probablement éviter.

67
SwiftArchitect

Swift 3.0 

DispatchQueue.main.async {
}
20
Eduardo Oliveros

Toute la mise à jour de la partie de l'interface utilisateur doit être déplacée dans le fil MAIN de l'App.

J'appelais un createMenuView () en arrière-plan et j'ai eu l'erreur ci-dessous

"Cette application modifie le moteur d'autolayout à partir d'un thread en arrière-plan, ce qui peut entraîner une corruption du moteur et des accidents étranges"

J'ai donc appelé la méthode ci-dessus dans le fil principal à l'aide de 

    DispatchQueue.main.async {
    }

dans Swift 3.0 et Xcode 8.0

Code correct écrit ci-dessous:

RequestAPI.post(postString: postString, url: "https://www.someurl.com") { (succeeded: Bool, msg: String, responceData:AnyObject) -> () in

        if(succeeded) {
            print(items: "User logged in. Registration is done.")

            // Move to the UI thread
            DispatchQueue.main.async (execute: { () -> Void in

                //Set User's logged in
                Util.set_IsUserLoggedIn(state: true)
                Util.set_UserData(userData: responceData)
                self.appDelegate.createMenuView()

            })

        }
        else {
            // Move to the UI thread
            DispatchQueue.main.async (execute: { () -> Void in
                let alertcontroller = UIAlertController(title: JJS_MESSAGE, message: msg, preferredStyle: UIAlertControllerStyle.alert)
                alertcontroller.title = "No Internet"
                alertcontroller.message = FAILURE_MESSAGE
                self.present(alertcontroller, animated: true, completion: nil)
            })
        }
    }
5
Anil Gupta

Devrait essayer Symbolic Breakpoint pour détecter le problème: -  enter image description here

Symbole:

[UIView layoutIfNeeded]`

État:

!(BOOL)[NSThread isMainThread]

Ensuite, mettez votre code de mise à jour de l'interface utilisateur dans le fil principal

DispatchQueue.main.async {}
3
Abdul Hameed

Vous disposez d'un code qui met à jour la présentation de l'interface utilisateur à partir d'un thread en arrière-plan . La modification de la file d'attente des opérations sur laquelle vous exécutez votre code n'a pas besoin d'être explicite. Par exemple, NSURLSession.shared () n'utilise pas la file d'attente principale lors de nouvelles requêtes. Pour m'assurer que votre code fonctionne sur le thread principal, j'utilise la méthode statique de NSOperationQueue, mainQueue ().

Rapide:

NSOperationQueue.mainQueue().addOperationWithBlock(){
    //Do UI stuff here
}

Obj-C:

[NSOperationQueue mainQueue] addOperationWithBlock:^{
    //Do UI stuff here
}];
3
Nikolay

Le même problème s’est produit dans mon cas, je dois changer le code de la manière suivante, puis cela fonctionne très bien . Dans ViewDidLoad, appelez cette méthode en utilisant main thread,

[self performSelectorOnMainThread:@selector(setUpTableRows) withObject:nil waitUntilDone:YES];
0
Preetha