Splash screen with activity indicator works fine in iOS6 but not in iOS5 - ios5

I would like to show a splash screen view with activity indicator to load some information from a server before entering inside my app. Below is how I do it:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
FeedViewController *feedViewController = [[FeedViewController alloc] initWithNibName:#"FeedViewController" bundle:nil];
MenuViewController *menuViewController=[[MenuViewController alloc] initWithNibName:#"MenuViewController" bundle:nil];
self.navController = [[UINavigationController alloc] initWithRootViewController:feedViewController];
IIViewDeckController* deckController = [[IIViewDeckController alloc] initWithCenterViewController:self.navController leftViewController:menuViewController rightViewController:nil];
deckController.panningMode=IIViewDeckNoPanning;
deckController.panningView=menuViewController.view;
self.window.rootViewController = deckController;
[self.window makeKeyAndVisible];
// show splash screen until data is loaded
SplashScreenViewController *controller = [[SplashScreenViewController alloc] initWithNibName:#"SplashScreenViewController" bundle:nil];
controller.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[feedViewController presentModalViewController:controller animated:NO];
return YES;
}
In FeedViewController.m, I did something like this:
- (void)viewDidLoad
{
// load data from a server
[self performSelector:#selector(dismissSplashScreen) withObject:nil afterDelay:0.0];
}
This code works very well with iOS6, but when I tested it with iOS5 the splash screen with activity indicator spinning just does not disappear. I suspect I might implement a splash screen in a wrong way. (But I don't understand why this works in iOS6?)

I solved this problem myself by using a bool variable to check whether the splash screen should be shown. The code for showing the splash screen is moved to viewDidLoad of FeedViewController instead.
This approach seems to work well for both iOS5 and iOS6.

Related

Unable to present a modal view controller completely over the top of a tab bar controller

I'm creating a tabbed iPhone application. When the application launches, if the user is not logged in, a modal view is supposed to be presented over the top of the tab bar controller (so it looks like this is the first screen). Upon login the modal view slides away to reveal the tab bar controller behind it.
Unfortunately when I call [self.tabBarController presentViewController:self.loginViewController animated:NO completion:NULL] from inside my application delegate I can still see the tabs along the bottom of the screen. I need them covered.
Ironically when searching for a solution, I find most people are having the inverse problem.
I have noticed that if I don't set my window's rootViewController to the UITabBarController, only inserting its view as a subview of the window, then it works as expected, but Xcode complains about the lack of rootViewController. What's going on here?
My application delegate's -application:didFinishLaunchingWithOptions: method looks like this.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[self registerDefaults];
self.tabBarController = [[[UITabBarController alloc] init] autorelease];
self.tabBarController.viewControllers = #[
[self makeSellingListingsController],
[[[UIViewController alloc] init] autorelease], // stub
[[[UIViewController alloc] init] autorelease], // stub
[[[UIViewController alloc] init] autorelease] // stub
];
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
self.window.rootViewController = self.tabBarController;
[self.window addSubview:self.tabBarController.view];
[self presentLogin]; // this doesn't cover the tabs, but it should
[self.window makeKeyAndVisible];
return YES;
}
- (void)presentLogin
{
[self.tabBarController presentViewController:[[[FLLoginViewController alloc]
initWithNibName:#"FLLoginViewController"
bundle:[NSBundle mainBundle]] autorelease]
animated:NO
completion:NULL];
}
Don't present it from the tab bar controller, but from the root controller in the first tab, in its viewDidAppear method. If you pass NO to the animation parameter, the modal screen will be the first thing you see when you start the app.

Parent view is not displayed after the low memory warning is received during MFMailCompose modal is open, canceled and draft saved/deleted

I have the following structure on my iPhone app
AppDelegate / UITabBarController / 5 UINavigationControllers(My tabs) / UIViewController(like rootViewController for each UINavigationController)
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
HomeViewController *homeViewController = [[HomeViewController alloc] init];
GoalsTableViewController *goalsTableViewController = [[GoalsTableViewController alloc] init];
HistoryViewController *historyViewController = [[HistoryViewController alloc] init];
SettingsViewController *settingsViewController = [[SettingsViewController alloc] init];
InfoViewController *infoViewController = [[InfoViewController alloc] init];
self.tabBarController = [[UITabBarController alloc] init];
self.tabBarController.delegate = self;
self.navBarActivity = [[UINavigationController alloc] initWithRootViewController:homeViewController];
self.navBarSettings = [[UINavigationController alloc] initWithRootViewController:settingsViewController];
self.navBarHistory = [[UINavigationController alloc] initWithRootViewController:historyViewController];
self.navBarGoals = [[UINavigationController alloc] initWithRootViewController:goalsTableViewController];
self.navBarAbout = [[UINavigationController alloc] initWithRootViewController:infoViewController];
self.tabBarController.viewControllers = [NSArray arrayWithObjects:self.navBarActivity, self.navBarGoals, self.navBarHistory,self.navBarSettings, self.navBarAbout, nil];
self.window.rootViewController = self.tabBarController;
[self.window makeKeyAndVisible];
return YES;
}
In some UIViewControllers I implemented a MFMailComposeViewController in order to send emails.
I experimented a weird issue (reproduced on simulator and real devices iOS 5.0 and 5.1)...
Using an iPhone Simulator (only iOS 5.0 or 5.1), if I simulate a low memory warning while a MFMailComposerViewController modal is open on the screen and then tap on Cancel and then tap on Delete|Save draft, when the modal is dismissed the parent view seems not visible (blanked view).
The life cycle seems work fine due, if I follow the same steps but after simulate a low memory warning I send the email from MFMailComposeViewController modal, when modal is dismissed, my parent view looks fine.
Any suggestions how to prevent my parent view from being unloaded on memory warning?
Edit1
I figured out what is happening, after unloading and comeback to the view and entering the last view within viewdidload(life cycle), the tabBar is not inserting navigation view. I check the subviews of tabBar:
UITransitionView
==><UIViewControllerWrapperView>
==> empty
<UITabBar>
I reintegrated the view of navigationBar by adding as subview in viewdidload:
UIView *tabBarControllerWrapperView = [[[self.tabBarController.view.subviews objectAtIndex:0] subviews] objectAtIndex:0];
// tabBar UIViewControllerWrapperView has not views
if([tabBarControllerWrapperView.subviews count] == 0)
{
// add navigationbar view
[tabBarControllerWrapperView addSubview:self.navigationController.view];
}
There is no better way to fix it, any thoughts?
After a memory warning is possible that on the non visible controllers is called viewDidUnload (iOS <= 5 ).In your case the view of the controller that presented the modal mailcomposer was probably unloaded.
The idea behind viewDidUnload is that you save the data you need to restore the view once viewDidLoad is called again. What you have to keep in mind is that your viewDidLoad can be called multiple times.
On iOS6 viewDidUnload is not called anymore, so this logic must be moved to didReceiveMemoryWarning

NavigationController not loading view

I'm using xCode 4.3.2 and started a blank application.
I have a navigation controller and a simple logincontroller. I want the login controller to be my root view so it is this first thing that a user does when they login.
I'm using the following code and when I run the application it displays a black screen. I put in logging in the LoginViewController.m->ViewDidLoad and it is being run is there something im doing wrong the LoginViewController.xib is very simple it just contains a button right now that will switch to a tab view controller once I figure this out.
Thanks in advance.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions
{
UIViewController *loginController = [[LoginViewController alloc] initWithNibName:#"LoginViewController" bundle:nil];
navigationController = [[UINavigationController alloc] initWithRootViewController:loginController];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
[self.window addSubview:navigationController.view];
[self.window makeKeyWindow];
return YES;
}
This is not right:
[self.window addSubview:navigationController.view];
change it to this:
self.window.rootViewController = navigationController;

View is not displaying after pushing on navigationController stack

I am trying to use a navigation controller to push/pop views, but I don't want the bar at the top with the buttons; I'm doing the navigation UI myself.
So I created a navigationController in my AppDelegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.viewController = [[WSViewController alloc] initWithNibName:#"WSViewController" bundle:nil];
self.window.rootViewController = self.viewController;
self.navController = [[UINavigationController alloc]
initWithRootViewController: self.viewController];
[self.window makeKeyAndVisible];
return YES;
}
and then in my WSViewController, I have an IBAction method that pushes another view on the navigation stack (I've verified that it's doing this correctly; I see it on the stack):
- (IBAction)showInfo:(UIButton *)sender {
if (self.wsInfoViewController == nil) {
WSInfoViewController *wic = [[WSInfoViewController alloc] initWithNibName:#"WSInfoViewController" bundle:nil];
self.wsInfoViewController = wic;
}
[self.navigationController pushViewController:self.wsInfoViewController animated:YES];
}
But I'm not seeing the info view show up when I tap on the info button in my WSViewController (which is showing up just fine).
If I make the navigationController the root controller, then I do see the wsInfoViewController when I tap on the info button, however, I also get the navigation bar at the top, which I don't want!
So... first, am I wrong in thinking I can use a navigation controller this way (i.e. using it for stack purposes but not for any UI at all)?
Second, if I'm not wrong, why isn't the view I'm pushing onto the stack showing up? I'm guessing it's because I'm not hooking the navigation controller up to the window correctly, but I'm not sure how to do that.
Thanks!!!
Elisabeth
So I think I have the answer to my question. Which is, you must set up the navigation controller as the root view controller for the AppDelegate window in order to use it, otherwise, the window doesn't know about it. My WSViewController is still the root view controller for the navigation controller. And then to get rid of the navigation bar, you can hide it.
Here's the updated code:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.viewController = [[WSViewController alloc] initWithNibName:#"WSViewController" bundle:nil];
// doesn't work!
//self.window.rootViewController = self.viewController;
self.navController = [[UINavigationController alloc]
initWithRootViewController: self.viewController];
// do this instead
self.window.rootViewController = self.navController;
[self.window makeKeyAndVisible];
return YES;
}
To hide the nav bar in the views, in each view where you want it hidden, add the following methods:
- (void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.navigationController setNavigationBarHidden:YES animated:animated];
}
- (void) viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[self.navigationController setNavigationBarHidden:NO animated:animated];
}
This is working great so far!

Show View Controller Modally on First Startup

I'd like to have a view with instructions on how to use my app show up on the first time the app is opened. I have handled the problem of the only showing this view on the first startup using NSUserDefaults, but I am having trouble getting the view to display the way I want it to modally, not as the rootViewController. Here is my AppDelegate.m code:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
self.viewController = [[[ViewController alloc] initWithNibName:#"ViewController_iPhone" bundle:nil] autorelease];
self.window.rootViewController = self.viewController;
BOOL hasShownStartup = [[NSUserDefaults standardUserDefaults] boolForKey:kAppHasShownStartupScreen];
if (!hasShownStartup) {
[self showInstructions];
}
[self.window makeKeyAndVisible];
return YES;
}
- (void)showInstructions
{
NSLog(#"showing instructions");
InstructionsViewController *howToView = [[InstructionsViewController alloc] initWithNibName:#"InstructionsViewController"
bundle:nil];
self.instructionsViewController = howToView;
[howToView release];
UINavigationController *howtoNavController = [[UINavigationController alloc]
initWithRootViewController:self.instructionsViewController];
self.instructionsViewController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self.viewController presentModalViewController:howtoNavController animated:NO];
[howtoNavController release];
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:kAppHasShownStartupScreen];
}
I want my rootViewController to remain self.viewController. I want to be able to click 'Done' on the instructionsViewController nav bar to transition back to the rootViewController. Executing the code as written never shows the instructions view. The only way I can see instructionsViewController is if I change the line [self.viewController presentModalViewController:howtoNavController animated:NO]; to self.window.rootViewController = self.instructionsViewController; but this is obviously not what i want (unless I could modally transition back to viewController).
Hopefully I've made it clear enough what I am trying to accomplish. Thanks in advance.
Try moving [self showInstructions]; to applicationDidBecomeActive: instead.
Try putting the [self showInstructions] after [self.window makeKeyAndVisible]:
[self.window makeKeyAndVisible];
if (!hasShownStartup) {
[self showInstructions];
}