Greetings,
I have a strange issue when calling .navigationController popViewControllerAnimated:YES from an NSOperation where the screen does not properly update and leaves the popped view visible but apparently deallocated.
Details: I have a list view that accesses a local sqlite database. When tapping on a record, it displays that record's detail view and kicks off an asynchronous NSOperation (on the main thread) to check the XML back end database to see if that record is still available in the database. For architectural reasons I won't get into, I can't run this operation on the list view, it must be in the detail view. If the record was deleted since the last synchronization, it notifies the user that the record has been deleted and calls the popViewControllerAnimated on a shared app delegate. Ideally, this would pop the current detail view and return to the previous list view.
Error: The proper view is in fact popped in memory (it has been deallocated) but it is still displayed on the screen. The navigation bar is blank, but I can click on the place where the "back" button should be, and it navigates to the start screen prior to the list view, meaning that at least the navigation bar understands where it's supposed to be, even if it's not displaying the title or back buttons properly. The primary issue is that the detail view is still visible and can be interacted with, which causes the application to crash. For example, the detail view also displays data in a UITableView and if the user scrolls down in the table, an exception is thrown "-[xAccountDetailController tableView:cellForRowAtIndexPath:]: message sent to deallocated instance"
This leads me to believe that the detail controller has been deallocated properly by the popViewControllerAnimated call, but obviously something still resides in memory, if the table actually calls the cellForRowAtIndexPath, even though it's view controller has been popped off the navigationController.
Manually pushing the back button while on the Detail view (for a record that wasn't deleted on the back end) works perfectly.
Workaround attempts: As I pass in to the NSOperation a reference to the detail view controller, I have attempted to call the popViewControllerAnimated from that view's navigationController property directly and from the shared app delegate. I've also tried to pop two views and re-push the list view onto the navigationController but that presents an even more disturbing interface effect where the root and list view controllers appear to be existing simultaneously in the navigation bar (the titles overwrite each other rather than being nonexistent). I've tried to set the reference to the detail view controller that exists in the NSOperation to nil, but that does nothing. I've tried calling a [detailView release] prior to popping, but as expected, it fails on the pop because it only had a retain count of 1 prior to the release. I've also tried popToViewController and popToRootViewController and nothing seems to work. The old view is always still there, the navigation bar is the only interface element that seems to do anything, and even then, it's displaying incorrectly. I've also tried reloading the table, because I don't really mind if the view stays visible (no popping), I just want to clear the data -- but the table won't reloadData for some reason.
Thoughts: As the operationQueue that's running the NSOperation is a property of the detail view in question, I've made sure that in the detail view's dealloc to cancelAllOperations and to set the reference to the operationQueue to nil. I've also tried to make sure that all references to that view in other objects have been set to nil. Calling popViewControllerAnimated directly from a button on the detail view works perfectly, so it must be the fact that I'm calling that method from the NSOperation, running on an NSOperationQueue that's a property of the detail view I want to pop. Some reference somewhere must be keeping that view partially alive, but I can't seem to find anything that's still referencing the view when the pop is called.
There's too much code in too many places to post any here.
Any thoughts?
Sorry for such a long question and thanks in advance,
Greg
Edit 1: I can reproduce this issue outside the NSOperation with a fresh UIViewController easily.
In a tableView:didSelectRowAtIndexPath
method I call the following:
xBaseViewController * vc = [[xBaseViewController alloc] initWithStyle:UITableViewStyleGrouped];
[self.navigationController pushViewController:vc animated:YES];
[vc performSelectorOnMainThread:@selector(popView) withObject:nil waitUntilDone:YES];
In vc, the popView method:
[self.navigationController popViewControllerAnimated:YES];
I don't think this has to do with retain counts or the NSOperation. Am I doing something fundamentally wrong with popping the view in this manner?