If I spawn a new thread, and then within it I push a new controller onto my UINavigationController, using code like this…
(a) not working
-(void)myCallbackInThread { // move on... UIApplication* app = [UIApplication sharedApplication]; [app changeView]; }
then I find that the view appears, but does not respond to user input.
If I change the code like this
(b) working
-(void)myCallbackInThread { // move on... UIApplication* app = [UIApplication sharedApplication]; [app performSelectorOnMainThread:@selector(moveToMain) withObject:nil waitUntilDone:FALSE]; }
Then everything works just fine.
Any hints as to why?
In your case, it really depends on what’s happening in [app changeView], but the reason it stops responding is most likely that you have no run loop dispatching events on your new, secondary thread (more on this below). In general, however, it is a very bad idea to update the GUI from a secondary thread. As you’ve already discovered, all of these events should go through the main thread.
The main reason that your second example works and not your first is that UIApplication sets up and handles the run loop and event dispatcher for you on the main thread. So, when you call performSelectorInMainThread, the selector gets dispatched to the main run loop which is able to then handle your gui input and other events. The event dispatcher is also run and managed by UIApplication on the main thread.
So basically, don’t perform any GUI management activities on a secondary thread. Dispatch those to the main thread. And if you need processing on a secondary thread (for things like timers or asynch calls, etc.) then you have to start and manage your own run loop on that thread (see NSRunLoop for more on managing your on run loop).