I get this log in the console when I am running my application in is simulator. Haven't seen this in iOS 8. I am not quite sure whats causing this. Has anyone else come across the same issue and if so how was it fixed? or is there any help anyone can provide in regards to this?
-
so .. https://github.com/nrbrook/NBUIKitMainThreadGuard – Fattie Feb 11 '17 at 16:26
-
Refer to this [post](http://stackoverflow.com/q/28302019/6521116) – LF00 May 17 '17 at 07:34
-
https://stackoverflow.com/a/58075072/8537648 – Govind Wadhwa Sep 24 '19 at 07:37
6 Answers
Do not change UI from anything but the main thread. While it may appear to work on some OS or devices and not others, it is bound to make your application unstable, and crash unpredictably.
If you must respond to a notification, which can happen in the background, then ensure UIKit
invocation takes place on the main thread.
You at least have these 2 options:
Asynchronous Dispatch
Use GCD
(Grand Central Dispatch) if your observer can be notified on any thread. You can listen and do work from any thread, and encapsulate UI changes in a dispatch_async
:
dispatch_async(dispatch_get_main_queue()) {
// Do UI stuff here
}
When to use GCD
? When you do not control who sends the notification. It can be the OS, a Cocoapod, embedded libraries, etc. Using GCD
will woke anytime, every time. Downside: You find yourself re-scheduling the work.
Listen on Main Thread
Conveniently, you can specify on which thread you want the observer to be notified, at the time you are registering for notifications, using the queue
parameter:
addObserverForName:@"notification"
object:nil
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification *note){
// Do UI stuff here
}
When to observe on main thread? When you are both registering and registered. Bu the time you respond to the notification, you are already where you need to be.
Post Notification On Main Thread
[self performSelectorOnMainThread:@selector(postNotification:) withObject:notification waitUntilDone:NO];
Hybrid solution which does not guarantee that the observer is only invoked from said method. It allows for lighter observer, at the cost less robust design. Only mentioned here as a solution you should probably avoid.

- 1
- 1

- 47,376
- 28
- 140
- 179
-
so we do make a couple of updates on the UI when we hear a notification, so are you saying that I need to make those updates inside "dispatch_async(dispatch_get_main_queue()"? – Shabarinath Pabba Aug 11 '15 at 21:16
-
-
alrighty, trying this now and will choose yours as an answer if it fixed it :D – Shabarinath Pabba Aug 11 '15 at 21:27
-
why was this not required in iOS 8?, why does this happen in iOS 9? – Shabarinath Pabba Aug 11 '15 at 21:29
-
1It was best practice well before iOS 8 - Apple has just chosen iOS 9 to start warning of improper updates, and, as the error states, will soon being disallowing UI updates on a background thread entirely. – Scott Austin Sep 17 '15 at 15:02
-
Do you know how can i find where is the problem? For me the changes before the warning were to make a scrollview and add the controller.view to it, and some more to support the change but i still can't find it. – Cristi Băluță Oct 24 '15 at 07:15
-
@http://stackoverflow.com/users/149202/cristi-b%c4%83lu%c8%9b%c4%83: you may want to ask a new question and post some code – SwiftArchitect Oct 25 '15 at 00:03
-
-
Great. See http://stackoverflow.com/a/34540787/218152 for a discussion on posting notifications on the main thread. – SwiftArchitect Jan 20 '16 at 14:32
All UI part updation you need to move into MAIN thread of App.
I was calling a createMenuView() into background and i got below error
"This application is modifying the autolayout engine from a background thread, which can lead to engine corruption and weird crashes"
So I called above method into Main thread Using
DispatchQueue.main.async {
}
in SWIFT 3.0 and Xcode 8.0
Correct code written below :
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)
})
}
}

- 1,155
- 1
- 19
- 26
Should try Symbolic Breakpoint to detect the issue:-
Symbol:
[UIView layoutIfNeeded]
Condition:
!(BOOL)[NSThread isMainThread]
Then put your UI Update code in main thread
DispatchQueue.main.async {}

- 11,183
- 13
- 64
- 87

- 1,025
- 13
- 17
You have code that updates the UI layout from a background thread. Changing the operation queue that you run your code on does not need to be explicit. For example NSURLSession.shared() does not use the main queue when making new requests. To ensure that your code runs on the main thread, I'm using NSOperationQueue's static method mainQueue().
Swift:
NSOperationQueue.mainQueue().addOperationWithBlock(){
//Do UI stuff here
}
Obj-C:
[NSOperationQueue mainQueue] addOperationWithBlock:^{
//Do UI stuff here
}];

- 1,076
- 1
- 13
- 11