iPhone loading screen until web request is finished - objective-c

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
});
});

Related

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/

Initiate self.window in appDelegate init method

I'm a web developer creating an Apache Cordova application so my knowledge with Objective-C is very little. Everything is going fine until i try to supplement the splash screen with a video. It sort of does it, but not fully.. It starts with displaying the Default.png followed by the SplashScreenLoader. It then actually plays the video and I know this because the audio is emitted, but the video layer isn't shown.
What I've found out is that the self.window or self.viewController are both defined in didFinishLaunchingWithOptions, so they don't exist in the - (id) init method. Therefore I can't find a way to place it on top of the loading splash.
My init method currently looks like this in AppDelegate.m:
- (id) init {
NSString *moviePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"Splash_v1.mp4"];
NSURL *movieURL = [NSURL fileURLWithPath:moviePath];
MPMoviePlayerController* moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL: movieURL];
moviePlayer.controlStyle = MPMovieControlStyleNone;
[moviePlayer.view setFrame: self.window.bounds];
[self.window addSubview:moviePlayer.view];
[self.window makeKeyAndVisible];
[moviePlayer play];
NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
[cookieStorage setCookieAcceptPolicy:NSHTTPCookieAcceptPolicyAlways];
[CDVURLProtocol registerURLProtocol];
return [super init];
}
Here the self.window is null, and I've also attempted to set the self.window with this code:
CGRect screenBounds = [[UIScreen mainScreen] bounds];
self.window = [[[UIWindow alloc] initWithFrame:screenBounds] autorelease];
...without prevail. It actually sets it, but for the subsequent code it doesn't wanna do it.
So what I'm wondering is, how would I place this video on top of the splash's content, before didFinishLaunchingWithOptions kicks in?
Thanks in advance,
//Peter
So what I'm wondering is, how would I place this video on top of the splash's content, before didFinishLaunchingWithOptions kicks in?
actually, you do that in didFinishLaunchingWithOptions. put this statements in there (in the bolierplate code that Xcode generates for you, you should already have a call to makeKeyAndVisible, so just complement it):
[self.window addSubview:moviePlayer.view];
[self.window makeKeyAndVisible];
having previously instantiated your moviePlayer.
One way to avoid the blank screen could be this:
create a UIImageView containing your Default.png image;
display such UIImageView by adding it to your self.window as a subview (this will create no black screen effect);
initialize your player (I assume it takes some time, hence the black screen) and add it below the UIImageView;
when the player is ready (viewDidLoad) push it on top of the UIImageView.
Finally, I don't know how your player will signal the end of the video play, but I assume you have some delegate method; make you appDelegate be also your player delegate and from there, remove UIImageView and player from self.window and add you other view to self.window.
Hope this helps.
EDIT:
This is a rough sketch of what I would try and do in your app delegate appDidFinishLaunching:
self.moviePlayer = <INIT MOVIEW PLAYER CONTROLLER>
self.backgroundImage = <INIT UIImageView with Default.png>
[self.window addSubview:self.moviePlayer.view];
[self.window addSubview:self.backgroundImage];
[self.window makeKeyAndVisible];
In your movie Player viewDidLoad:
- (void)viewDidLoad {
[super viewDidLoad];
...
[self.view.superview addSubview:self.view]; //-- this will just move the player view to the top
...
}
If that helps anyone else, I had the same issue which was resolved by moving '[self.window makeKeyAndVisible];' above the subview like this, so in appdelegate.m:
UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 300)];
myView.backgroundColor = [UIColor blueColor];
[self.window makeKeyAndVisible];
[self.window addSubview:myView];
This works fine, but if I swap the last two statements around, the subview does not display.

Launch screen delay works in iOS Simulator but not Device

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.

Seamlessly flip from one modal view to another, without showing a solid colour background

I have the following UI for an iPad app:
When I click on the Settings button, I want the dialog to horizontally flip to show the settings dialog.
I have this working fine. But, there is a background colour shown when the dailog flips over. As you can see:
Is there any way to not have this block of colour be visible as the dialogs flip? I'd like it to look more seamless -- as if it's a sheet of paper flipping over.
The views are essentially this:
Window
Main View. Set to the window's rootViewController
Login modal view
Thus the main window and root controller are setup as follows (in the app delegate class):
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.viewController = [[MainViewController alloc] initWithNibName:#"MainView" bundle:nil];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
The login window is setup and shown in the main view's viewDidAppear:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
// Setup and show Login dialog
LoginViewController* controller = [[LoginViewController alloc] initWithNibName:#"LoginView" bundle:nil];
controller.delegate = self;
controller.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
controller.modalPresentationStyle = UIModalPresentationFormSheet;
[self presentModalViewController:controller animated:YES];
}
And when the Settings button is pressed: showing the Settings modal view is done in pretty much the same way that the Login modal view was shown:
- (IBAction)settingsButtonPressed:(id)sender {
SettingsViewController *controller = [[SettingsViewController alloc] initWithNibName:#"SettingsView" bundle:nil];
controller.delegate = self;
controller.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
controller.modalPresentationStyle = UIModalPresentationCurrentContext;
[self presentModalViewController:controller animated:YES];
}
I don't think there's any way to do what you want using the modalPresentationStyle. You'll need to implement the animation yourself using a transition animation using the following method:
+ (void)transitionFromView:(UIView *)fromView toView:(UIView *)toView duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options completion:(void (^)(BOOL finished))completion
With the UIViewAnimationOptionTransitionFlipFromLeft option.
In this case the new view you want to flip is not the content of the modal (the controller.view) but the modal frame itself, so experiment with just calling the method above from your settings button, and instead of passing controller.view, substitute controller.view.superview, and if that doesn't work, try controller.view.superview.superview until the animation looks right.
It will require some tweaking to work out exactly how to do it.

Adding admob to base appdelegate so it can be persistent thoughout all views

I want to add admob to the base app delegate so that I can have a persistent ad that will show though out all views instead of refreshing the every time i change the view Controllers.
"bannerView_.rootViewController = self;" is the problem i do not know how to get this to work across all the view controllers. How can I from the base app delegate be able to get the current viewcontroller displayed on the app.
This is the code that i have currently in app delegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Create a view of the standard size at the bottom of the screen.
bannerView_ = [[GADBannerView alloc]
initWithFrame:CGRectMake(0.0,
self.window.frame.size.height -
GAD_SIZE_320x50.height,
GAD_SIZE_320x50.width,
GAD_SIZE_320x50.height)];
// Specify the ad's "unit identifier." This is your AdMob Publisher ID.
bannerView_.adUnitID = #"a14e0dssddb01d";
// Let the runtime know which UIViewController to restore after taking
// the user wherever the ad goes and add it to the view hierarchy.
bannerView_.rootViewController = self;
// Initiate a generic request to load it with an ad.
[bannerView_ loadRequest:[GADRequest request]];
//[self.window addSubview:navController.view];
[self.window addSubview:bannerView_];
[self.window makeKeyAndVisible];
return YES;
}