Getting a “This application is modifying the autol

2018-12-31 21:21发布

问题:

Been encountering this error a lot in my OS X using swift:

\"This application is modifying the autolayout engine from a background thread, which can lead to engine corruption and weird crashes. This will cause an exception in a future release.\"

I have a my NSWindow and I\'m swapping in views to the contentView of the window. I get the error when I try and do a NSApp.beginSheet on the window, or when I add a subview to the window. Tried disabling autoresize stuff, and I don\'t have anything using auto layout. Any thoughts?

Sometimes it\'s fine and nothing happens, other times it totally breaks my UI and nothing loads

回答1:

Okay - found the answer. It needs to be placed inside a different thread that allows the UI to update as soon as execution of thread function complete :

Swift 3

 DispatchQueue.main.async {
    // Update UI
 }

Swift Version < 3

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

Objective-C Version

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


回答2:

You get similar error message while debugging with print statements without using \'dispatch_async\' So when you get that error message, its time to use

Swift 4

DispatchQueue.main.async { //code }

Swift 3

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

Earlier Swift versions

dispatch_async(dispatch_get_main_queue()){ //code }


回答3:

Used @markussvensson answer to detect my problem, found it using this Symbolic Breakpoint:

  1. Symbols: [UIView layoutIfNeeded] or [UIView updateConstraintsIfNeeded]
  2. Condition: !(BOOL)[NSThread isMainThread]

\"enter



回答4:

When you try to update a text field value or adding a subview inside a background thread, you can get this problem. For that reason, you should put this kind of code in the main thread.

You need to wrap methods that call UI updates with dispatch_asynch to get the main queue. For example:

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

EDITED - SWIFT 3:

Now, we can do that following the next code:

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


回答5:

For me, this error message originated from a banner from Admob SDK.

I was able to track the origin to \"WebThread\" by setting a conditional breakpoint.

\"conditional

Then I was able to get rid of the issue by encapsulating the Banner creation with:

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

I don\'t know why this helped as I cannot see how this code was called from a non-main-thread.

Hope it can help anyone.



回答6:

I had this problem since updating to the iOS 9 SDK when I was calling a block that did UI updates within an NSURLConnection async request completion handler. Putting the block call in a dispatch_async using dispatch_main_queue solved the issue.

It worked fine in iOS 8.



回答7:

Had the same problem because I was using performSelectorInBackground.



回答8:

You must not change the UI offside the main thread! UIKit is not thread safe, so that above problem and also some other weird problems will arise if you do that. The app can even crash.

So, to do the UIKit operations, you need to define block and let it be executed on the main queue: such as,

NSOperationQueue.mainQueue().addOperationWithBlock {

}


回答9:

Obviously you are doing some UI update on back ground thread. Cant predict exactly where, without seeing your code.

These are some situations it might happen:-

you might be doing something on background thread and not using. Being in the same function this code is easier to spot.

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

calling a func doing web request call on background thread and its completion handler calling other func doing ui update. to solve this try checking code where you have updated the UI after webrequest call.

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


回答10:

I had this issue while reloading data in UITableView. Simply dispatching reload as follows fixed the issue for me.

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


回答11:

I had the same problem. Turns out I was using UIAlerts that needed the main queue. But, they\'ve been deprecated.
When I changed the UIAlerts to the UIAlertController, I no longer had the problem and did not have to use any dispatch_async code. The lesson - pay attention to warnings. They help even when you don\'t expect it.



回答12:

You already have the correct code answer from @Mark but, just to share my findings: The issue is that you are requesting a change in the view and assuming that it will happen instantly. In reality, the loading of a view depends on the available resources. If everything loads quickly enough and there are no delays then you don\'t notice anything. In scenarios, where there is any delay due to the process thread being busy etc, the application runs into a situation where it is supposed to display something even though its not ready yet. Hence, it is advisable to dispatch these requests in a asynchronous queues so, they get executed based on the load.



回答13:

I had this issue when I was using TouchID if that helps anyone else, wrap your success logic which likely does something with the UI in the main queue.



回答14:

It could be something as simple as setting a text field / label value or adding a subview inside a background thread, which may cause a field\'s layout to change. Make sure anything you do with the interface only happens in the main thread.

Check this link: https://forums.developer.apple.com/thread/7399



回答15:

I had the same issue when trying to update error message in UILabel in the same ViewController (it takes a little while to update data when trying to do that with normal coding). I used DispatchQueue in Swift 3 Xcode 8 and it works.



回答16:

For me the issue was the following. Make sure performSegueWithIdentifier: is performed on the main thread:

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


回答17:

Swift 4,

Suppose, if you are calling some method using operation queue

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

And suppose function searchFavourites is like,

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

if you call, all code inside the method \"searchFavourites\" on the main thread, it will still give an error if you are updating some UI in it.

This application is modifying the autolayout engine from a background thread after the engine was accessed from the main thread.

So use solution,

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

For this kind of scenario.



回答18:

I also encountered this problem, seeing a ton of these messages and stack traces being printed in the output, when I resized the window to a smaller size than its initial value. Spending a long time figuring out the problem, I thought I\'d share the rather simple solution. I had once enabled Can Draw Concurrently on an NSTextView through IB. That tells AppKit that it can call the view\'s draw(_:) method from another thread. After disabling it, I no longer got any error messages. I didn\'t experience any problems before updating to macOS 10.14 Beta, but at the same time, I also started modifying the code to perform work with the text view.