My app shows a splash screen. How can I make my test wait for the main screen? - earlgrey

My app shows a splash screen. How can I make my test wait for the main screen to appear? Without waits my test fails immediately after app launch.
// in application:didFinishLaunchingWithOptions: of my AppDelegate...
SplashViewController *splashVC = [[SplashViewController alloc] init];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.rootViewController = splashVC;
[self.window makeKeyAndVisible];
NSTimeInterval splashScreenDuration = 0.5;
[NSTimer scheduledTimerWithTimeInterval:splashScreenDuration
target:self
selector:#selector(hideSpashScreenAndDisplayMainViewController)
userInfo:nil
repeats:NO];
// hideSpashScreenAndDisplayMainViewController method simply sets self.window.rootViewController to the main view controller.

EarlGrey provides the GREYCondition API that you can use in your setup method or the beginning of your specific test to make EarlGrey wait while you wait for the splash screen to disappear. You can do this using code similar to what they have in their faq page.
// Wait for the main view controller to become the root view controller.
BOOL success = [[GREYCondition conditionWithName:#"Wait for main root view controller"
block:^{
id<UIApplicationDelegate> appDelegate = [UIApplication sharedApplication].delegate;
UIViewController *rootViewController = appDelegate.window.rootViewController;
return [rootViewController isKindOfClass:[MainViewController class]];
}] waitWithTimeout:5];
GREYAssertTrue(success, #"Main view controller should appear within 5 seconds.");

Related

UITabBarController tabbaritem not touchable after second click

I have an UITabBarController added programmatically one ViewController as ModalViewController.
It acts perfectly normal, when touching/switchen between the tabs.
But when touching the selected tab again, the delegate didselectviewcontroller did not get called.
Strange behaviour, if I setup a new project with TabBarController template, this is acting normal and everytime I touch a tab its delegate is being called.
What I noticed, if I touch 2-5px above the tabbar, the tab is being touched and the delegate is being called.
There is no view above the tabbar, I checked this 100 times.
if I touch in the lightgray area, the touch on the tab is being fired.. thats a miracle to me, anybody any idea?
Code:
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.tabBarController = [[UITabBarController alloc] init];
_splashScreen = [[SplashScreenController alloc] initWithNibName:#"SplashScreenView" bundle:nil];
self.window.rootViewController = _splashScreen;
[self.window makeKeyAndVisible];
if finished loading data in background,
//getting UIViewControllers from Config and adding to NSMutableArray *tbcArr;
[self.tabBarController setViewControllers:tbcArr];
self.tabBarController.customizableViewControllers = nil;
self.tabBarController.delegate = self;
[self.splashScreen presentModalViewController:self.tabBarController animated:YES];

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.

Splash screen with activity indicator works fine in iOS6 but not in 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.

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;

Show login screen before tab-controller view

i have a tabBarController application and using .xib files for the interface not the storyboard
i have this code by default in the appdelegate
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
UIViewController *viewController1 = [[PopAdsFirstViewController alloc] initWithNibName:#"PopAdsFirstViewController" bundle:nil];
UIViewController *viewController2 = [[PopAdsSecondViewController alloc] initWithNibName:#"PopAdsSecondViewController" bundle:nil];
self.tabBarController = [[UITabBarController alloc] init];
self.tabBarController.viewControllers = [NSArray arrayWithObjects:viewController1, viewController2, nil];
self.window.rootViewController = self.tabBarController;
[self.window makeKeyAndVisible];
return YES;
i have created a Login View and don't know how to show it before the tabBarView and hide t after a successful login.
One way would be to show it as a modalView on launch. Dismissing upon successfull login?
eg:
UIViewController myLoginViewController = [[MyLoginViewController alloc] init withNibNamed:"MyLoginViewController"]; //Or whatever you instantiation is
[myTabViewController presentModalViewController:myLoginViewController animated:YES];
And to dismiss it (Hide it)
//This should be done from the original View Controller i.e. myTabViewController preferably in a delegate called by the modal view controller.
[self dismissModalViewControllerAnimated:YES];
Documentation on modalViewControllers:
http://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/ModalViewControllers/ModalViewControllers.html
The way that I did it for one of my apps is to just add them in the correct order. Add your tabbar controller to your window, then add the login controller over the top of the tab bar. Then show your window. The user won't see anything but your login controller. Once you login, you can just remove the login controller from view.
This way is probably best if you have information you need to hide until login. The other way is to only launch the login view only. On successful login, remove the login and add the tab bar controller. Either way is fine.
Presenting modally is probably the easiest, but requires a view in place before presenting. So if the data and view under the login controller isn't that sensitive, you could consider this option.
Another way would be using LoginViewControllerDelegate in your appDelegate.h file
In your .h
#import "yourLoginViewController"
//and add LoginViewControllerDelegate
Then in your .m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
yourLoginViewController *loginView = [[yourLoginViewController alloc] initWithNibName:#"yourLoginViewController" bundle:nil];
loginView.delegate = self;
[window addSubview:loginView.view];
[window makeKeyAndVisible];
}
//add this one
- (void)loginViewControllerDidFinish:(yourLoginViewController *)loginViewController {
[window addSubview:tabBarController.view];
}