How to break your UIView with nothing but a background queue

I recently found myself tearing my hair out over some very odd behaviours in XCode. Giving focus to a text view wasn't bringing up the keyboard, but I could still type where the keyboard should have appeared. I spent days trying various tweaks and changes to get it working, blaming this library and that library, but as it turned out, the solution was very simple.

PERFORM YOUR SEGUES ON THE MAIN QUEUE!

I'm aware I'm shouting, and you may think it's obvious, since you should run all you UI operations on the main queue. But I spent three days trying to figure this one out, that if one person remembers this, I'll have done my good deed for the year. It's so important, I'm going to repeat it.

PERFORM. YOUR. SEGUES. ON. THE. MAIN. QUEUE!

Got it? Awesome. Wondering what might happen if you get this wrong? I've put together a simple demo on GitHub that reproduces the problem and shows what can happen when you run into it. In short, it can turn a view like this:

SecondScreen-MainQueue

 

into this:

SecondScreen-BackgroundQueue

At least until something triggers a redraw of the view, which can take a few minutes. This is only the most obvious manifestation of the problem, if you see it, it may appear in a later view, or, as in my case, a misbehaving keyboard.

The solution to this is simple:

PERFORM YOUR SEGUES ON THE MAIN QUEUE!

This could be an involved process, requiring careful consideration of the flow to each of your segues, specifically where they're called in blocks, or using asynchronous code.

Alternatively, you could just wrap them all in a dispatch block:

dispatch_async(dispatch_get_main_queue(), ^(void){
   [self performSegueWithIdentifier:@"detailSegue" sender:self];
});

I hope this saves someone the pain I had to go through. Just don't forget to perform your segues on the main queue.