Resolution: While trying to recreate this bug in a fresh project to submit to Apple, I discovered that it is specific to iPhone OS 2.1, and compiling for 2.2 fixes the problem. Stephen, thanks for your help; I’ll be accepting your answer since it would have worked if the bug still existed or I wasn’t willing to compile for 2.2.
I have an app which is radically changing its database schema in a way that requires me to transform old-style records to new-style ones in code. Since users may store a lot of data in this app, I’m trying to display a modal view controller with a progress bar while it ports the data over (i.e. as the very first thing the user sees). This view controller’s viewDidAppear: begins a database transaction and then starts a background thread to do the actual porting, which occasionally uses performSelectorInMainThread:withObject:waitUntilDone: to tell the foreground thread to update the progress bar.
The problem is, viewDidAppear: is being called twice. I noticed this because that ‘start a transaction’ step fails with a ‘database busy’ message, but setting a breakpoint reveals that it is indeed called two times—once by -[UIViewController viewDidMoveToWindow:shouldAppearOrDisappear:], and again by -[UIViewController modalPresentTransitionDidComplete]. Those names appear to be private UIViewController methods, so I’m guessing this is either a framework bug, or I’m doing something UIKit isn’t expecting me to do.
Two relevant code excerpts (some irrelevant code has been summarized):
- (void)applicationDidFinishLaunching:(UIApplication *)application { (register some default settings in NSUserDefaults) // doing this early because trying to present a modal view controller // before the view controller is visible seems to break it [window addSubview:[self.navigationController view]]; // this is the method that may present the modal view [self.databaseController loadDatabaseWithViewController:self.navigationController]; if(!self.databaseController.willUpgrade) { [self restoreNavigationControllerState]; } }
And from my DatabaseController class:
- (void)loadDatabaseWithViewController:(UIViewController*)viewController { (open the new database) (compute the path the old database would live at if it existed) if([[NSFileManager defaultManager] fileExistsAtPath:oldDBPath]) { (open the old database) [viewController presentModalViewController:self animated:NO]; } }
So, is there something I’m screwing up here, or should I file a bug report with Apple?
I saw this in my app too. I never got it entirely confirmed, but I think this is what’s happening:
In my case I just reset what happened in the first call to
viewDidAppear:.In your case two options spring to mind: a static variable to track whether you’ve started the upgrade already; or look at the
UIView*parameter passed in before starting.