I have a simple table view where I handle the select action on the table view. This action follows a segue.
If the segue is a push segue, the next view
There seem to be various situations when performing a segue will not work properly. For example, if you call performSegue from the action handler of an unwind segue, you will run into various issues, even though you are on the main thread. On my current project, I am calling performSegue from the didSelectRowAt method of a table view. This is one of the most basic segues there is and of course I am on the main thread, yet I was seeing the exact symptoms that the OP described.
I do not know why this happens in some cases and not others, but I have found that deferring the performSegue call using async fixes any potential issues. This used to seem like a hack and made me nervous, but at this point I have several mature projects using this approach and it now seems like the "right" way to do a manual segue.
Here is the Swift 3 version of the code (see the other posts for Swift 2 and Obj-C versions):
DispatchQueue.main.async {
self.performSegue(withIdentifier: "theIdentifier", sender: theSender)
}