I'm creating an iPad app with a tab bar controller that requires login. So on launch, I want to show a LoginViewController and if login is successful, then show the tab bar controller. This is how I implemented an initial test version (left out some typical header stuff, etc)...
AppDelegate.h:
@interface AppDelegate_Pad : NSObject
<UIApplicationDelegate, LoginViewControllerDelegate> {
UIWindow *window;
UITabBarController *tabBarController;
}
@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet UITabBarController *tabBarController;
@end
AppDelegate.m:
@implementation AppDelegate_Pad
@synthesize window;
@synthesize tabBarController;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
LoginViewController_Pad *lvc = [[LoginViewController_Pad alloc] initWithNibName:@"LoginViewController_Pad" bundle:nil];
lvc.delegate = self;
[window addSubview:lvc.view];
//[lvc release];
[window makeKeyAndVisible];
return YES;
}
- (void)loginViewControllerDidFinish:(LoginViewController_Pad *)loginViewController {
[window addSubview:tabBarController.view];
}
- (void)dealloc {...}
@end
LoginViewController_Pad.h:
@protocol LoginViewControllerDelegate;
@interface LoginViewController_Pad : UIViewController {
id<LoginViewControllerDelegate> delegate;
}
@property (nonatomic, assign) id <LoginViewControllerDelegate> delegate;
- (IBAction)buttonPressed;
@end
@protocol LoginViewControllerDelegate
-(void)loginViewControllerDidFinish:(LoginViewController_Pad *)loginViewController;
@end
LoginViewController_Pad.m:
@implementation LoginViewController_Pad
@synthesize delegate;
...
- (IBAction)buttonPressed
{
[self.view removeFromSuperview];
[self.delegate loginViewControllerDidFinish:self];
}
...
@end
So the app delegate adds the login view controller's view on launch and waits for login to call "did finish" using a delegate. The login view controller calls removeFromSuperView before it calls didFinish. The app delegate then calls addSubView on the tab bar controller's view.
If you made it up to this point, thanks, and I have three questions:
MAIN QUESTION: Is this the right way to show a view controller before the app's main tab bar controller is displayed? Even though it seems to work, is it a proper way to do it?
If I comment out the "lvc release" in the app delegate then the app crashes with EXC_BAD_ACCESS when the button on the login view controller is pressed. Why?
With the "lvc release" commented out everything seems to work but on the debugger console it writes this message when the app delegate calls addSubView for the tab bar controller: Using two-stage rotation animation. To use the smoother single-stage animation, this application must remove two-stage method implementations. What does that mean and do I need to worry about it?
UPDATE: As suggested by lucius, changed it to modally show the login view controller from the app delegate. This appears to be a cleaner solution. Code changed as follows...
AppDelegate.m:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[window addSubview:tabBarController.view];
[window makeKeyAndVisible];
LoginViewController_Pad *lvc = [[LoginViewController_Pad alloc] initWithNibName:@"LoginViewController_Pad" bundle:nil];
lvc.delegate = self;
[self.tabBarController presentModalViewController:lvc animated:NO];
[lvc release];
return YES;
}
-(void)loginViewControllerDidFinish:(LoginViewController_Pad *)loginViewController {
[self.mainTabBarController dismissModalViewControllerAnimated:NO];
}
LoginViewController_Pad.m:
- (IBAction)buttonPressed
{
//do NOT removeFromSuperview, delegate will dismiss
//[self.view removeFromSuperview];
[self.delegate loginViewControllerDidFinish:self];
}
I'd use the method to present the view controller modally instead of adding it to the window. That will make it properly retain the controller. The debugger message has to do with certain autorotation methods being implemented in your class. You can ignore it for now.