I'm writing a game for iOS and I was wondering how to make the instructions View Controller open every time the app is opened. I want to have a switch that says "Show me this every time." and if they switch it to no the instructions will no longer show up when the app is opened.
You can use NSUserDefaults to store the switch value, then check for it every time app launches in Your app delegate, applicationDidBecomeActive method.
- (void)applicationDidBecomeActive:(UIApplication *)application
{
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
BOOL switchState = [[NSUserDefaults standardUserDefaults] boolForKey:#"switchKey"];
if(switchState) {
//If switch is on create the instance of InstructionViewController
//you can call any of InstructionViewController methods on it.
InstructionViewController* intructionsViewController = [[InstructionViewController alloc] init];
//Present the instance of instruction view on top of your current view
[self.window.rootViewController presentViewController:controller animated:YES completion:nil];
}
}
Related
I receive a pust notification and push a view controller based on the data i get in push.
I do it like this:
UINavigationController *navVc=(UINavigationController *) self.window.rootViewController;
PictureTakeVC *pvc=[[PictureTakeVC alloc] init];
[navVc pushViewController:pvc animated:NO];
It works, but the view controller that was opened before i pressed home button shows for a moment.
I also tried this but it happens the same:
PictureTakeVC *pvc=[[PictureTakeVC alloc] init];
NSArray *vcs=[[NSArray alloc] initWithObjects: pvc, nil];
UINavigationController *navVc=(UINavigationController *) self.window.rootViewController;
navVc.viewControllers=vcs;
self.window.rootViewController = navVc;
How to push vc didReceiveRemoteNotification so that it opens immediatly and no other vc is shown for a moment?
As you said "but the view controller that was opened before i pressed home button shows for a moment.",
The reason is not the code, but the iOS system.
It captures screenshot of the screen when app goes in background. As documented:
Remove sensitive information from views before moving to the
background. When an app transitions to the background, the system
takes a snapshot of the app’s main window, which it then presents
briefly when transitioning your app back to the foreground. Before
returning from your applicationDidEnterBackground: method, you should
hide or obscure passwords and other sensitive personal information
that might be captured as part of the snapshot.
So, if snapshot is removed then it will directly show the new pushed view controller.
(not sure about apple guideline for snapshot)
Update:
One approach can be:
Add a black colored background on the app screen when it goes in background(in applicationDidEnterBackground method). So, it will show black screen while coming back to application.{ They store it for showing launch image for already started application.}
Where it helps?
When we delete snapshots from 'Preference' directory of application sandbox(after application goes in background) and come back to application it shows black for a while as it does not have any snapshot.
The outcome of our approach and removing snapshot are same.
Since PictureTakeVC is a view controller just use this instead
PictureTakeVC *pvc = [[PictureTakeVC alloc] initWithNibName:#"PictureTakeVC" bundle:nil];
[self.navigationController pushViewController:pvc animated:YES];
Before your app goes into background mode remove the view that is there.
Are you missing something? The didReceiveRemoteNotification fires when your application is active and running.
...but anyway if you want to achieve what you are asking you have to detect there is a pushnotification from didFinishLaunchingWithOptions (or may be from applicationDidBecomeActive or applicationWillEnterForeground) and push viewcontroller on rootviewcontroller from one of these methods.
To detect whether there were remote notification:
NSString *params = [[launchOptions objectForKey:#"UIApplicationLaunchOptionsRemoteNotificationKey"] objectForKey:#"View"];
if (params)
{
// push view
}
Use following methods to push view, you won't see any other vc when application gets activated. Let me know if any issues.
- (void)applicationWillEnterForeground:(UIApplication *)application
{
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
}
I have done similar for push notification so let me know what are you trying to achieve exactly if I understood wrong.
In my app I'm downloading lots of images on a method.
I'm using a
downloadTask = [[UIApplication sharedApplication]
beginBackgroundTaskWithExpirationHandler:^{
[[UIApplication sharedApplication] endBackgroundTask:downloadTask];
downloadTask = UIBackgroundTaskInvalid;
}];
This is working fine, if I press the home or sleep button, the images continue downloading.
I'm showing the progress in a UIProgressView inside an UIAlertView, and when the percent is 100% the alertView is dissmised and I change the viewController to other where I show the donwloaded images.
But I only want this to happen if the app is really active at the moment the download finish.
I have been looking at the app state and while it's downloading with the screen off.
[UIApplication sharedApplication].applicationState
the state is UIApplicationStateActive during all the donwload
How can I can know if the downloading is happening with the screen off or on?
EDITED AFTER ACCEPTING THE ANSWER:
I just discovered, if I tap the home button, the app enters in UIApplicationStateBackground, if I tap the wake/sleep it enters in UIApplicationStateInactive
Following the approach of the correct answer, my app contines donwloading in both cases.
The screen is off in two states (apart from when the app has not been even opened):
suspended : in this case you don't have to worry because the download won't procede until the app gets active again; It will enter this state on
background : it's in this state for a limited amount of time before going in suspend, and the screen is already off in this moment. Here you may want to check then whether to do all the things you said or not, because in this state code can be still executed. In this state the app status is UIApplicationStateBackground, so you could just perform a check like this:
You probably want to check whether the app is in background execution in order to achieve the result. Just like this:
if([[UIApplication sharedApplication] applicationState] != UIApplicationStateBackground) {
// Do stuff
}
If it's in background, so the screen is off.
UPDATE: after few test, what I figured out is that the behaviour you are expieriencing is probably due to the execution of the download on the main thread.
You should send the download on (for instance) the global queue. This way the application will enter the background state as expected:
....
[[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[[UIApplication sharedApplication] endBackgroundTask:self.bti];
}];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self doBackgroundStuff];
});
....
This way, if the app is put on background while the download is in progress, the application state will turn into UIApplicationStateBackground, and then you can check it as I wrote initially. If you are doing UI updates during the progress remember to send them back to the main thread (because the download is now on a different one).
You can check whether your app is running in the background or not by setting a flag in the designated application delegate methodsapplicationDidEnterBackground: and applicationWillEnterForeground:. Example:
- (void)applicationDidEnterBackground:(UIApplication *)application
_applicationRunsInForeground = NO;
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
_applicationRunsInForeground = YES;
}
If you don't want to have this _applicationRunsInForeground flag inside your application delegate, you could observe the delegate's NSNotifications in your viewcontroller class instead (UIApplicationWillEnterForegroundNotification and UIApplicationDidEnterBackgroundNotification).
With iOS 5, push notifications can appear as banner and disappear after a few seconds.
I understand that didReceiveRemoteNotification will be called when user taps on the banner.
My question is, if the banner has disappeared and my user sees that there is a badge number on the app, they will tap on the app icon to start the app. Now if the app is running in the background, how do I check that the app is brought to foreground and there has been a notification, and do the necessary?
The purpose of my notification is basically to inform user there has been an update to the app content and encourage them to run the app to get the latest contents. My app only checks for latest contents at launch time and doesn't check for updates periodically.
This question is a bit old, but I'll pop what I've found in here anyway.
There are two methods you need to implement in your app delegate to check if your app was either launched from the remote notification (From when the app is not running on your device), or received the remote notification while running (in the background or foreground).
First is a method that is already in your App Delegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
To check if this was launched from a remote notification, have some code similar to this:
// Check to see if launched from notification
if (launchOptions != nil)
{
NSDictionary* dictionary = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (dictionary != nil)
{
NSLog(#"Launched from push notification: %#", dictionary);
// DO SOMETHING HERE
}
}
The other method you will need to implement is specifically for the case that your application for when your application is running:
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
NSLog(#"Received notification: %#", userInfo);
}
How you handle the notification from there is up to you, but that's how your app knows about it!
In this second method, you can check the UIApplicationState of the passed application to find out if you were in the foreground or background.
I´m building an app for iphone.
I have two views. The first time the user starts the app, i wanna show the 1st view, he pushes a button and go´s to the 2nd view.
The 2nd time he starts the app, i want it to jump directly to the 2nd view.
Can you guys point me in the right direction?
I would use the NSUserDefaults for this
-(BOOL) shouldSkipFirstView
{
//boolForKey returns NO if that entry does not exist or is not associated with a bool
return [[NSUserDeafults standardUserDefaults] boolForKey:#"shouldSkipFirstView"];
}
-(void) skipFirstViewInFuture
{
[[NSUserDeafults standardUserDefaults] setBool:YES forKey:#"shouldSkipFirstView"];
[[NSUserDeafults standardUserDefaults] synchronize]; //optional line
}
-(UIViewController*) getStartupViewController
{
if([self shouldSkipFirstView])
{
[self skipFirstViewInFuture];
return [[[MySecondViewController alloc] init] autorelease];
}
else
{
return [[[MyFirstViewController alloc] init] autorelease];
}
}
You should look into NSUserDefaults. The concept will be to store a value as a preference the first time the app loads and show the 1st view. Then each time your app opens, check if that preference value is set and if so, display the 2nd view.
Create variable and save it to NSUserDefaults so first time when app is loaded set it to true and show view 1 and set it to false. Second time if it is false show view 2 and set it to true.
Code should be in app did finish launching in app delegate.
You just need some kind of record that the app has been opened. You could for example store an object in NSUserDefaults containing the version of the app, which is set on app did finish launching. You can then check to see if there is an object for that key at all, or if the recorded version is lower than the current version of the app (if you want to, for example, show it every time the version changes).
I am using UILocalNotification. When the notification shows, and the user clicks my alertAction, how can I direct them to a specific view when my app loads? (Similar to how the calendar app shows you the event that just was alerted).
I am using:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOption {
UILocalNotification *localNotif = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
if (localNotif) {
NSString *itemName = [localNotif.userInfo objectForKey:ItemListKey];
// [viewController displayItem:itemName]; // custom method
application.applicationIconBadgeNumber = localNotif.applicationIconBadgeNumber-1;
NSLog(#"has localNotif %#",itemName);
}
return YES;
}
You need to structure your application view controllers so that you can show a particular view from within the applicationLaunch. That may mean, for example, programmatically re-creating your entire view controller structure without the benefit of any user interactions. You may have to manually select tab bar tabs, manually create navigation controller stacks, etc.
Edit: additionally, there are three cases to handle with local notifications:
the app receives the local notification and was brought from background to foreground (so all your view controller structures are already intact, but you still have to manually "navigate" to the right place)
the app receives the local notification and was already running in the foreground
the app was just launched