I know this question has been asked but the methods are not working for me. I have a view controller that contains a tutorial, which I only want to display as the initial view the first time the app is opened. After that, the main menu will always be the initial view. The storyboard ID for my Tutorial screen is "Tutorial". I have the following code to detect first launch, but I can't figure out how to make the tutorial appear:
- (void)viewDidLoad
{
if ([[NSUserDefaults standardUserDefaults]boolForKey: #"FirstLaunch"])
{}
else{
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"FirstLaunch"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
You can change initial controller in two ways:
Check 'Is Initial VC' checkbox at Interface Builder or
Configure it at -application:didFinishLaunchingWithOptions: method
Changing initial view controller using Application Delegate
In -application:didFinishLaunchingWithOptions: in your application delegate (AppDelegate.m) add if/else to check the necessity of tutorial:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
if (![[NSUserDefaults standardUserDefaults] boolForKey: #"FirstLaunch"])
{
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"FirstLaunch"];
[[NSUserDefaults standardUserDefaults] synchronize];
/*** load vc ***/
}
return YES;
}
To set the initial controller you have to initialize window property, create vc and set it as root:
// 1. Initialize window
self.window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
// 2. Get storyboard
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
// 3. Create vc
TutorialViewController *tutorialViewController = [storyboard instantiateViewControllerWithIdentifier:NSStringFromClass([TutorialViewController class])];
// 4. Set as root
self.window.rootViewController = tutorialViewController;
// 5. Call to show views
[self.window makeKeyAndVisible];
Hope it helps!
Related
Using NSUserDefaults, I'm able to present one view if it is the first launch and then another view if it isn't. My problem is, no matter what, the program thinks its the first launch. My code is as follows (in my AppDelegate.m file):
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc]initWithFrame:[[UIScreen mainScreen ]bounds]];
NSString *storyboardID;
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
bool hasLaunched = [defaults boolForKey:#"hasLaunched"];
if (!hasLaunched) {
storyboardID = #"firstLaunch";
hasLaunched = YES;
[defaults synchronize];
}
else {
storyboardID = #"notFirstLaunch";
}
UIStoryboard *main = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController *viewController = [main instantiateViewControllerWithIdentifier:storyboardID];
UINavigationController * navControl = [[UINavigationController alloc]initWithRootViewController:viewController];
self.window.rootViewController = navControl;
[self.window makeKeyAndVisible];
return YES;
}
I'm creating a nav controller programmatically. Another strange thing is that the first launch view controller (which always shows up) has a transparent nav bar over it. However, when I push to a different view controller (by presenting it), the second view controller doesn't have a nav bar over the top. I'm not sure why this would be the case, considering I'm moving the nav controller over to a new view controller.
You are setting the local variable hasLaunched to YES, but you are not storing this variable in NSUserDefaults -
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
bool hasLaunched = [defaults boolForKey:#"hasLaunched"];
if (!hasLaunched) {
storyboardID = #"firstLaunch";
[defaults setBool:YES forKey:#"hasLaunched"];
}
else {
storyboardID = #"notFirstLaunch";
}
I don't really understand your second question. I suggest you ask another question and include screen shots of your issue.
I'm working on an app that changes it's rootViewController depending on it's state. To make a switch I use this code:
- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[self createManagedDocumentAndContext];
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSString *storyboardId = [userDefaults boolForKey:#"Profile Created"] ? #"User Stats" : #"Profile";
self.window.rootViewController = [self.window.rootViewController.storyboard instantiateViewControllerWithIdentifier:storyboardId];
return YES;
}
To switch back I call this method from presented ProfileVC:
- (void)returnOldRootViewController
{
UIWindow *currentWindow = [UIApplication sharedApplication].keyWindow;
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
OLDUserStatsVC *userStatsVC = [storyboard instantiateViewControllerWithIdentifier:#"User Stats"];
userStatsVC.userProfile = self.userProfile;
[currentWindow setRootViewController:userStatsVC];
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setBool:YES forKey:#"Profile Created"];
}
THE PROBLEM: rootViewController is changed, but previous one is not deallocated. It stays on the "background" of the app - I can see it when VC changes to another one.
The question is how to release it properly?
Thank you very much!
The real problem here is that you are changing the root view controller of the window. Don't do that. You should be setting this once and never again. There should be just one root view controller for the lifetime of the app.
Find another architecture for displaying the correct view controller and switching between them as desired. For example, they might both be children of the root view controller, or one might be a presented view controller in front of the other.
I get this error in Xcode: #interface for AppDelegate declares the selector performSegueWithIdentifier:sender:.
My main.storyboard has a seque from the regular view to the one for the first launch.
My AppDelegate.m says this:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
if ([[NSUserDefaults standardUserDefaults] boolForKey:#"HasLaunchedOnce"])
{
// app already launched
NSLog(#"this app has already been launched partner");
}
else
{
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"HasLaunchedOnce"];
[[NSUserDefaults standardUserDefaults] synchronize];
// This is the first launch ever
NSLog(#"first time launch bb");
[self performSegueWithIdentifier:#"toWelcomeScreen" sender:self];
}
// Override point for customization after application launch.
return YES;
}
How do I make it so on the first launch, it shows the view with segue toWelcomeScreen?
-performSegueWithIdentifier:sender: is not a method defined in the <UIApplicationDelegate> protocol, therefore it cannot be called on self in this context. Subclasses of UIViewController can respond to the message -performSegueWithIdentifier:sender:, so call this on the AppDelegate's window's rootViewController property.
[self.window.rootViewController performSegueWithIdentifier:#"toWelcomeScreen" sender:self];
Make sure you have assigned a rootViewController before this call.
Edit: rootViewController is a property of the the AppDelegate's window.
Edit 2: to assign the rootViewController property, just set it to an instance of your custom view controller.
self.window.rootViewController = [[MyCustomViewControllerThatIWantToSegueTo alloc] init];
I'm trying to setup a first-launch view in my iOS application. To do this I have the following code to allow me to execute code when the application launches for the first time.
What I want, is when the application launches for the first time, the user is sent to the FirstLaunch view that I've setup in Storyboards, instead of the FirstView view. Every consecutive launch will send the user to the FirstLaunch view.
Currently, I have this code executing in the NavigationController.m, but if this would be better executed in the AppDelegate.m I can change it.
if ([[NSUserDefaults standardUserDefaults] boolForKey:#"FirstLaunch"])
{
// not first launch
}
else
{
// first launch
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"FirstLaunch"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
My question is: How do I setup a segue programably (or activate a segue) to send the user to the FirstLaunch view instead of the normal FirstView?
You do not need a segue for that - all you need is a way to pick the initial view controller programmatically, based on whether or not it's the first launch.
To do that, uncheck the "is initial view controller" in the storyboard on your FirstView, and change your app delegate as follows:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
// Use the name of your storyboard below
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MyStoryboard" bundle:nil];
NSString *initialId;
if ([[NSUserDefaults standardUserDefaults] boolForKey:#"FirstLaunch"]) {
// not first launch
initialId = #"FirstViewController";
} else {
// first launch
initialId = #"FirstLaunchViewController";
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"FirstLaunch"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
self.window.rootViewController = [storyboard instantiateViewControllerWithIdentifier:initialId];
[self.window makeKeyAndVisible];
return YES;
}
The code above embeds your code that decides if this is a first launch or not, and sets the storyboard identifier of the target screen based on this decision.
Note that this implementation will never show the user the first launch screen again, even if he didn't get a chance to take a good look the first time that it showed up (e.g. because someone called him, or the device ran out of battery power). A better approach is to read the NSUserDefaults in the same way that you do, but to set it to YES only when the first launch controller is dismissed by the user. This way you would be certain that the user has had enough time to see the screen and interact with it.
In your storyboard set up identifier for segue you need (select segue and choose Attributes Inspector).
After that you can call that segue programmatically:
[self performSegueWithIdentifier:#"indentifier" sender:nil];
This well explained article on segue will answer your question
http://www.appcoda.com/storyboards-ios-tutorial-pass-data-between-view-controller-with-segue/
Sample block of activating and passing data with segue :
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"showRecipeDetail"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
RecipeDetailViewController *destViewController = segue.destinationViewController;
destViewController.recipeName = [recipes objectAtIndex:indexPath.row];
}
}
The Creating a segue programmatically and View Controller Programming Guide for iOS would be good references.
How could i create a modal view , maybe from the delegate to check if its the first time the application launches and show a modal view with a dismiss button , in order to inform the user about something important?
I need the view to show ONLY the first time the application is launched and never again.
Firstly: Check out an earlier answer of mine here: https://stackoverflow.com/a/13563490/1359306
This is for a password protection modal view which I use every time the app is opened. The answer should help a few issues that may arise when implementing your solution. It uses performSegueWithIdentifier as I am using storyboards, but you could also use presentViewController:animated:completion: to present you view.
Then: Note that there is an if statement in place which you can use check if you need to present the view or not. In my case I check to see if the user has been out of the app for more than 5 minutes. I do this by setting a date in NSUserDefaults each time applicationWillResignActive is called - and checking the difference between that and the current date/time).
In your case you could do something like the following:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if ([defaults objectForKey:#"firsttime"] == nil) {
//display modal view
[defaults setObject:#"YES" forKey:#"firsttime"];
[defaults synchronize];
}
This checks the NSUserDefaults of the app. If 'firsttime' is nil (which it will be when app is first downloaded) we will show the view. We then set the key to "YES" which means it will never equal nil again - so the view will never show.
This is useful for showing instructions when the app first loads. Alternatively, you could store dates or numbers to make the code more adaptable in the future.
The docs for NSUserDefaults can be found here.
You can achive this using NSUserDefaults.
In delegate.h file
NSString * firstTime;
In .m file
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.viewController = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *myStr = [defaults objectForKey:#"str"];
firstTime =myStr;
if (firstTime.length==0) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"hi" message:#"You have open this app first time" delegate:self cancelButtonTitle:#"ok" otherButtonTitles: nil];
[alert show];
[self firstTime];
}
return YES;
}
-(void)firstTime
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *myStr = #"first";
[defaults setObject:myStr forKey:#"str"];
[defaults synchronize];
}
in your AppDelegate using method didFinishLaunchingWithOptions check if your application is launching first time or 2nd time like this
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
if ([[NSUserDefaults standardUserDefaults] boolForKey:#"firstTime"])
{
// show your main view controller
}
else
{ // your app is launching first time ....
// show your modalview controller here and dismiss it & go to main view controller
// don't forget to update the key so that next time user don't hang in else statement...
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"firstTime"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
}
You can use the presentViewController:animated:completion: in the UIViewController class.
So here is what I'd do:
Load your main view controller
Check your user preferences to see if your "firsttime" key exists (in your view did load most likely)
If it doesn't display your one-time view
When it completes (which you can know by having a delegate call back to your main view controller), save the "firsttime" key to your user preferences
no source, code (my Mac is at home), but if you follow these simple steps it should work fine for you.