Main Thread Checker

I'm receiving this warning when running my applicaiton: Main Thread Checker: UI API called on a background thread: -[UIWindow rootViewController]

In my code because of the navigation construction I often need to grab a reference of the main rootviewcontroller. I do this like this:


UIViewController *rootViewController = appDelegate.window.rootViewController;

It appears that this reference is what is causing the warning. So how do I gain a refrence to the main rootviewcontroller without this warning?

You should enclose the call by a statement to run it in the main thread.


In Swift, you should write

DispatchQueue.main.async {
     // Call the rootViewController
}


I think in ObjC, would be:

dispatch_async(dispatch_get_main_queue(), ^(void) {
     UIViewController *rootViewController = appDelegate.window.rootViewController; 
    });

I think you're getting the warning because the UIWindow "rootViewController" property is settable, and the setter must run on the main thread. The getter would seem to be safe, since it (presumably) doesn't mutate anything, but there is a potential race condition if the getter and setter happen to run simultaneously in different threads.


In many apps, the main window's rootViewController never changes, so this race condition can't occur. In that case, I suggest you add a readonly property such as "mainViewController" to your app delegate, which you initialize to "window.rootViewController" during your app's startup. That should silence the warning, and (since it never changes) can't be subject to a race condition.


If you do change your rootViewController during execution, you're going to have to arrange some kind of thread safety guarantee. You could use a dispatched block as Claude suggested, but I'd use "sync" rather than "async". Just be careful you don't use it anywhere that might cause a deadlock.

Threads are beyond me - I leave that to my more esteemed expert colleagues.


But I notice one thing that confuses me, perhaps the compiler handles it with aplumb or perhaps it also confuses the compiler.


You are using a name that is already used by the system. I'd change it to:

UIViewController *myRootViewController = appDelegate.window.rootViewController;

It doesn't confuse the compiler in this case, for two reasons:


1. The property name is declared within the NSWindow class. It won't be recognized as that property name unless it is in a context that specifies a window, such as "….window.rootViewController".


2. In Obj-C, the declaration is a local variable, which is different from a property. The property is backed by an instance variable, but currently the default name of the instance variable would be "_rootViewController", not "rootViewController".


Thus, the local variable "rootViewController" is unambiguous in the OP's context.

Main Thread Checker
 
 
Q