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:
- Load root view
- Load modal view
- OS sends view did appear notification for the view in step 1
- The current view controller, which in this instance happens to be your DatabaseController class, picks it up
- OS sends the view did appear notification for the modal view
- The current view controller gets the notification. In this case it's the exact same controller as last time
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.Brent Royal-Gordon : As I noted above, I eventually discovered it was fixed in OS 2.2, but thanks for your suggestion.Stephen Darlington : No problem. Great to see the "real" answer!
0 comments:
Post a Comment