views:

952

answers:

1

Greetings! I have a working iPhone app (huzzah!) that uses a MainView.xib containing a fully-stocked UITabBar with several UINavigationController objects and views at-the-ready.

I've now been asked to add a one-time registration view to this mix. This view would appear before the UITabBar at app-launch, get some info from the user, register with a server - or check for an existing registration, then squirrel some data away in the keychain. (If the keychain already shows proof of registration, then we skip showing this particular view.)

The registration and keychain part I've got under control (thank you Erica Sadun for the latter!), but showing that initial one-time view is proving to be trickier than I expected.

I suspect I'm too close to the problem to see what's wrong. I really hope it's pilot error and doesn't require anything too Rube Goldberg!

Here's the scenario:

The app starts by loading MainView.xib, in which lies the aforementioned UITabBar controller, et. al. For the sake of argument, let's say we must show that registration view. Also, we'd like it to have a modal appearance, so it will fly in from the bottom up. Then, when we're done, we can dismiss it, call a delegate (most likely the App Delegate) and tell it to carry on with the original UITabBar.

// Normally, the Tab Bar Controller's view is added to the window ... still do this?
[window addSubview:tabBarController.view];

// We could now set up a VC like so. Mostly harmless. (I know, "mvc" is an unfortunate abbreviation in this case.)
RegistrationVC *mvc = [[RegistrationVC alloc] initWithNibName:@"RegistrationView" bundle:nil];

Note that RegistrationView.xib has a UIView inside, but no nav controller. We want to keep it decoupled so that it can be reused, say, as part of a tab bar item's nav controller (to review your registration info, for instance).

Moving on. We create a nav controller with the intent of presenting things modally:

UINavigationController *nc = [[UINavigationController alloc] initWithRootViewController:mvc];

We then present our modal VC, using the tab bar controller as the basis, and release the alloc'ed bits.

[tabBarController presentModalViewController:nc animated:YES];
[nc release];
[mvc release];

First observation. Something tells me this is just plain sloppy. You can see the first tab bar item's nav bar and view appear just as the modal view swoops in. Yeccch! Moreover, trying to set the selected VC to nil beforehand has no effect:

 tabBarController.selectedViewController = nil;

We really don't want/need to use the tab bar until after the modal VC is done (and we have the delegate to help let us know when that happens).

Why am I even bothering with the Tab Bar? Well, it looks like I need something to hang that modal VC's hat on, and I don't know what else there is to use.

Is this the only way? It just seems to tether the Registration VC and the Tab Bar unnecessarily, and it just smells ... wrong.

Clues welcome/appreciated!

+1  A: 

It's hard to answer this without knowing what your Default.png shows. Assuming you're following the HIG and it displays an empty tabBarController, I'd suggest a somewhat complicated layering: bottom view: tabBarController.view middle view: UIImageView: Default.png top view: registration view positioned below the bottom of the screen

On startup, if you need to show the registration view, manually animate it upward, and once the animation is done remove the UIImageView below it. When registration is complete, manually animate the registration view downward to reveal the tabBarController. If on startup you don't need the registration view, just animate the UIImageView to fade away (or just remove it).

OTOH hand, if you're not following the HIG and instead showing some kind of splash screen, things get a bit easier. Layer like this: bottom view: tabBarController.view top view: UIImageView: Default.png

If you need to show registration, do presentModalViewController with animated:NO and then fade out the UIImageView. If not, just fade out the UIImageView.

That's a lengthy explanation w/o pictures, hope it makes sense. The salient point is that I'm suggesting adding a UIImageView:Default.png to be the first thing that is seen when the app starts, and use that to guide your transition into registration or tabBarController as appropriate.

Neil Mix
Thanks Neil! I should clarify: It doesn't follow the HIG (splash screen - I know, boo hiss). I'm already doing a fadeout to the tab bar ( see http://is.gd/4GnwP ). So - we now fade to an interim "Welcome" VC that's a muted version of the splash (just an image view, nudged down 20px for the status bar). From there we pause briefly, toss up a welcome alert, show the modal VC (with animation!). After that, we're back at the interim VC. One more thank-you, then the final reveal, bringing in the tab bar with a final fadeout to the main app. Whew! Plays nicely now. Re-reading your method too. Thx!!
Joe D'Andrea
OK! I re-read your post just to make sure I understand. With the registration view off-screen (doing a manual animation up/down), where does the navigation bar (controller?) fit in to that? I'm always used to just pushing a VC on to a nav controller, and I think this is where I was tripping up before. There was noplace to hang that VC, modal or otherwise, and this is why I now have this interim view controller (instead of the tab bar controller, which is waiting in the wings). But I get what you're saying with the layering being anything but basic. Ahh, the things we do for UE. :)
Joe D'Andrea
Well, you could use just a plain-old-view, rather than a ViewController. Or is there some reason you need to put the registration in a ViewController, such as needing a nav bar on it?
Neil Mix
Neil - first my apologies for dropping the ball on replying to this! (Another email I just received jogged my memory.) To your followup about using a plain-old-view, you nailed it. I ended up taking a plain view containing a nav bar and other goodies, and just added that as a subview to window. The app delegate takes a breather while this new VC handles the detour. When that's done, and we've animated the view off, we tell the app delegate and it tears things down and resumes startup. I suspect it's not the cleanest route (read: I can do better) but it gets the job done! Again, many thanks.
Joe D'Andrea