Launch screen delay works in iOS Simulator but not Device - objective-c

I've set my launch screen to only display for 1 second using the code below sleep(1); in the app delegate, but when testing directly on a device, I have to wait for the full 5 seconds.
Every time I run a test using an iPhone, or an iPad, I have to wait the full 5 second default before the app will load, however, it works great in the simulator.
If I unplug the iPhone cable, the sleep() function works on the devices. Is there a setting in xCode for this?
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
sleep(1);
...
}

In order to delay the launch screen this is not the recommended method. This just delays the whole process.
I recommend you add a new viewController to the very beginning of your project which will show immediately after the launch screen with a UIImageView containing the exact same image as the launch Image.
Then add a delay from there before switching to the original first screen. This way you can even add a new different kind of transition to the launch image.
#import "OrginalController.h"
- (void) gotoOrginalFirstScreen
{
// This function will take you to your oringinal first screen
// from the temporary screen with the launch image
OrginalController *controller = [[OrginalController alloc] initWithNibName:#"OrginalController" bundle:nil];
controller.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentViewController:controller animated:YES completion:nil];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// add this line to call the transition and the delay
[self performSelector:#"gotoOrginalFirstScreen" withObject:nil afterDelay:1.0];
}

you can display the launch screen without putting it to sleep itself. You don't need a separate view controller also. This method will work anywhere and wont trouble you also.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"splashscreen.png"]];
imageView.frame = CGRectMake(0, 0, 324, 480);
[window addSubview:imageView];
[self.window makeKeyAndVisible];
[self performSelector:#selector(firstscreen) withObject:nil afterDelay:1.0];
return YES;
}
-(void)firstscreen
{
// Load some View
}
this you can put it in you application delegate this will show your splash image for 1 sec after which the next screen will be loaded.

Related

iPhone loading screen until web request is finished

I need to show "Loading screen" (just an image) at the start of application and when application gets all needed data from web, then first viewcontroller is shown. I have succeded doing it by setting my own black screen "Default.png" as "LoadingScreen.png" (Of course named again as Default.png) and
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.viewController = [[THWViewController alloc] initWithNibName:#"THWViewController" bundle:nil];
[self performSelector:#selector(start) withObject:nil afterDelay:5.0];
[self.window makeKeyAndVisible];
return YES;
}
- (void)start
{
self.window.rootViewController = self.viewController;
}
I would change that random delay to when api loading is finished, but is this a good way of implementing it ? Because i get that message that rootviewcontroller is expected.
You might want to consider using a block so you can eliminate that random delay. I would also consider calling this from your first view rather than starting with no root (remove the warning):
//show your loading screen over your first view
dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Get all the needed data
dispatch_async( dispatch_get_main_queue(), ^{
// do what you need to do with data and in first view
//hide the loading screen
});
});

Unable to detect iPhone Retina 4-inch screen size in simulator

I want to make my iOS application support iPhone 5. So I created a separate xib set for iPhone 5 size. Then I load each xib by checking the screen height.
This is the splash screen loading code inside the AppDelegate.m:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
// Override point for customization after application launch.
UIViewController *viewController1;
if ([UIScreen mainScreen].bounds.size.height==480) {
viewController1 = [[SplashScreen alloc] initWithNibName:#"SplashScreen" bundle:nil];
}
if ([UIScreen mainScreen].bounds.size.height==568) {
viewController1 = [[SplashScreen alloc] initWithNibName:#"SplashScreen5" bundle:nil];
}
self.window.rootViewController = viewController1;
[self.window makeKeyAndVisible];
return YES;
}
But when I change the simulator into Retina 4-inch, my code doesn't get the emulator size. It always executes the 480 if condition.
But other apps I created like this are working properly.
What is the reason for this?
I'm having the exact same problem right now (at the worst moment, of course....).
It did work properly for several weeks, and for a unknown reason, the simulator suddenly considers the 4in simulated device as a 3.5in screen.
cleaning, reset, reboot : same situation...
EDIT : ok, problem solved. T'was because of a missing Default image in the -568#2x format. I knew that was a condition to make the system work, but xcode had apparently decided to get rid off the one I chose. oh well...

self.navigationController == nil after awaking from LocalNotification

I'm working in Xcode 4.3.2
I implemented Local Notifications that alert the user of a new event at a predetermined time. So when my app is in the background and the clock strikes 8 am (for instance), the user will get a notification from my app.
When the user decides to view the app from the background I load a nib. Currently, this nib works properly: it shows the view as it was it arranged in the nib. However, after the nib is shown to the user, I want to forward the user to a different view in the LocalNotificationsHandler.m. When I attempt to push the second view, my app fails. So while there isn't an error message, it seems the second nib will not load.
In short the flow goes as follows:
user gets notification while my app is running in the background
user chooses to view the app
the LocalNotificationsHandler nib will load
self.navigationController == nil (in LocalNotificationsHandler.m)
self.navigationController will not "[pushViewController: "new view" animated:YES]" to get a new view
I'm wondering if there is something I'm missing from my AppDelegate.m file so I've included
"didFinishLaunchingWithOptions" from my AppDelegate.m file:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
// Add the navigation controller's view to the window and display.
NSLog(#"did finish launching with options");
[self.window addSubview:tabBarController.view];
[self.window makeKeyAndVisible];
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound)];
if (self.locationManager == nil)
{
locationManager = [[CLLocationManager alloc] init];
locationManager.purpose = #"We will try to use you location";
}
if([CLLocationManager locationServicesEnabled])
{
[self.locationManager startUpdatingLocation];
}
self.navigationController.navigationBar.tintColor = nil;
return YES;
}
You are using the outdated (since iOS 3) method of adding the viewcontroller's view to the main UIWindow. That should be looking like this:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// create properly sized window
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// create instance of root VC and assign to window
MainViewController *vc = [[MainViewController alloc] init];
self.window.rootViewController = vc;
[vc release];
[self.window makeKeyAndVisible];
return YES;
}
The navigationController property of a view controller is ONLY set if it is actually presented from a UINavigationController.
See this writeup for more information: http://www.cocoanetics.com/2012/11/revisited/

Set a new window.rootViewController before the view gets loaded

So I am trying to install this Navigation Framework in my app:
https://github.com/weissi/FRLayeredNavigationController
http://www.youtube.com/watch?v=k9bFAYtoenw&feature=plcp
Now, if you look at the attached image, I have my login screen. Once the login is done, I do a Segue Modal push into my "home" page and in there, I want to start having the FRLayeredNavigationController once I reach my homepage. Is that possible while using the storyboard? According to the Youtube Video, one would usually use the FRLayeredNavigationController by doing:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
HomeViewController* homeController = [[HomeViewController alloc] init];
FRLayeredNavigationController* lnc = [[FRLayeredNavigationController alloc] initWithRootViewController:homeController];
self.window.rootViewController = lnc;
}
[self.layeredNavigationController pushViewController:vc inFrontof:self maximumWidth:NO animated:YES];
I have not fount a way to do this using Segue's... But the way I have accomplish this is as follows:
Providing the login was successful and you are wanting to move onto the next part of you app, then the following is how you would transition:
- (void)loginSucceeded
{
UIViewController * vc = (UIViewController*)[self.storyboard instantiateViewControllerWithIdentifier:#"someIdentifier"];
FRLayeredNavigationController * nav = [[FRLayeredNavigationController alloc] initWithRootViewController:vc configuration:^(FRLayeredNavigationItem *item) {
item.width = 300;
item.nextItemDistance = 90;
}];
[self presentViewController:nav animated:YES completion:nil];
}
You will need to set the Storyboard ID to that specified in the above methos. This can be found in the 'Identity Inspector' tab when viewing the storyboard and selecting the ViewController you have designed.
Also you will no longer need to perform the segue you had previously created, so delete that.
Any future view controllers you want to 'push' onto the screen, you simply need to call the following:
UIViewController * vc = (UIViewController*)[self.storyboard instantiateViewControllerWithIdentifier:#"SomeStoryboardIDHere"];
[self.layeredNavigationController pushViewController:vc inFrontOf:self maximumWidth:YES animated:NO];

Adding splashscreen to iphone app in AppDelegate

I'm running xcode-4.2 and the project is based for ios5 using storyboards.
I've created a single view application , using the template provided by Apple.
In the storyboard I the removed the viewcontroller created for me and added a UITabBarController.
Next I added a new class MyTabBarController which is a subclass of UITabBarController.
Now I want to show a splashscreen before the TabBar appears. So I can do some loading and calculation in the background.
I thought AppDelegate.m would be a good place for this. Since that's the place where my rootview get's loaded not ? Or should a show the splashscreen from the rootviewcontroller which is MyTabBarController in my case ?
So I created a xib file. I'm surprised you can add .xib files to ios5 storyboard projects. The xib file is called SplashView.xib it has a single view with an image on it.
Code in AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
_splashScreen = [[UIViewController alloc] initWithNibName:#"SplashView" bundle:nil];
//_splashScreen is defined as:#property (strong, nonatomic) UIViewController *splashScreen;
[_window.rootViewController presentModalViewController:_splashScreen animated:NO];
[self performSelector:#selector(hideSplash) withObject:nil afterDelay:2];
return YES;
}
The problem is nothing happens. Even if I change the value from 2 to 200. The application starts up as if there is no splashscreen.
As you might have noticed I'm still struggling with the design of objective-c and iphone application. I hope a decent answer to my question will bring some clarity to the subject.
Thanks in advance!
Splash screens are built into iOS apps. All you need to do is create a file called Default.png and Default#2x.png (for retina displays) and it will work as a splash screen for when the app launches.
You can also set what these images will be in your apps info.plist.
I've dealt with a few clients who wanted to use an animated splash.
Though I'm totally against this, following Apple's HIG,
those clients just don't understand...
Anyway, since - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions; has to return boolean,
it's very important not to halt it for anything.
Also, since launch time is measured by iOS, if it's taking too long, the app will be terminated by iOS!
For this reason, I often use - (void)applicationDidBecomeActive:(UIApplication *)application;
with some kind of flag to indicate if it happened at launch or at returning from background mode.
Or, you should use a NSTimer or - (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay;
so, didFinishLaunchingWithOptions can return without being blocked for processing your animated splash.
This delayed performSelector should be implemented not only for hiding action (like the way you intended it), but also for starting the animation.
If you are using storyboard, you can just add the splash UIImageView to your window.rootViewController.view like this:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UIImage *splashImage = [UIImage autoAdjustImageNamed:#"Default.png"];
UIImageView *splashImageView = [[UIImageView alloc] initWithImage:splashImage];
[self.window.rootViewController.view addSubview:splashImageView];
[self.window.rootViewController.view bringSubviewToFront:splashImageView];
[UIView animateWithDuration:1.5f
delay:2.0f
options:UIViewAnimationOptionCurveEaseInOut
animations:^{
splashImageView.alpha = .0f;
CGFloat x = -60.0f;
CGFloat y = -120.0f;
splashImageView.frame = CGRectMake(x,
y,
splashImageView.frame.size.width-2*x,
splashImageView.frame.size.height-2*y);
} completion:^(BOOL finished){
if (finished) {
[splashImageView removeFromSuperview];
}
}];
return YES;
}
I think the reason why directly just add the UIImageView to window is because iOS will bring the rootViewController.view to front when the default splash will hide. And this will overlap the animation. This means the animation does happen but it's behind the rootViewController.
I just add an identical image to the launch image to my first view controller and then fade it (or whatever animation you require) - this avoids pausing the app load in the AppDelegate.
You need to ensure that the image has the same size and origin as your launch image e.g. to set the image to display on my first view controller which is a tableViewController:
UIImageView *imageView = [[UIImageView alloc] initWithFrame:self.tableView.bounds];
imageView.image = [UIImage imageNamed:#"[imagename]"];
[self.tableView addSubview:imageView];
[self.tableView bringSubviewToFront:imageView];
// Fade the image
[self fadeView:imageView];
-(void)fadeView:(UIView*)viewToFade
{
[UIView animateWithDuration:FADE_DURATION
animations:^ {
viewToFade.alpha = 0.0;
}
];
}