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.
Related
I currently have a launch screen storyboard with an image set up as my loading screen.
I'm used to doing everything programmatically, and storyboarding is throwing me for a ride. I have a boolean set up to determine if this is the first time the app is being launched. If so, I want to have one view controller that I set as the root of my navigation controller. If it isn't the first launch, I want to set a different root view controller to my nav controller.
I've clicked and dragged a navigation controller onto my storyboard. I just don't know what to do with it now. I have a viewController set up with an image that I'd like to be the first thing seen if it is the first time the app is being launched. However, I'm not sure what is automatically initialized using storyboard, so conceptually I'm not sure how to set up my app.
Since I have to handle this condition programmatically, do I even need to create a nav controller in storyboard, or would that be redundant?
My parent VC (viewController) is just an image with a label overlaid on top. Building with the below code in my appDelegate.h file correctly shows my launch screen storyboard, but then fades to a black screen.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
firstLaunch = YES;
if (firstLaunch == YES) {
ViewController *launchScreen = [ViewController new];
UINavigationController * navControl = [[UINavigationController alloc]initWithRootViewController:launchScreen];
self.window.rootViewController = navControl;
firstLaunch = NO;
}
else {
// create instance of other view controller and set as root of navigation controller
}
return YES;
}
Any ideas as to why my app is just navigating to a black screen?
Make sure to use
[window makeKeyAndVisible];
I usually do this in my application like so:
self.window = [[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds];
self.navController = [[UINavigationController alloc]init];
self.window.rootViewController = self.mainViewController;
[self.window makeKeyAndVisible];
In addition, your code will always say it's the user's first time. I would recommend using NSUserDefaults as such:
BOOL hasLaunchedBefore = [[NSUserDefaults standardUserDefaults] boolForKey:#"HasLaunchedBefore"];
if (!hasLaunchedBefore) {
//All your first launch UI stuff
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"HasLaunchedBefore"];
[[NSUserDefaults standardUserDefaults] synchronize];
} else {
//Not first launch
}
I've been trying to change the initial view in app delegate by putting this code
if(![[NSUserDefaults standardUserDefaults] valueForKey:#"userId"]) {
LogInViewController* lvc = [[LogInViewController alloc]init];
[self.navigationController pushViewController: lvc animated:YES];
}else {
PerfilViewController *pvc = [[PerfilViewController alloc]init];
[self.navigationController pushViewController: pvc animated:YES];
}
i have swrevealviewcontroller in my storyboard as its shown beneath, the red one is the one when its not logged in and the blue one is when its logged in
Try this. Instead of having multiple arrows, have only one that points to the very first view (LogInViewController). Then, in the viewDidLoad function of LogInViewController, place your checker code. You could then have a segue from LogInViewController over to PerfilViewController that is performed if the user is logged in; otherwise, stay on LogInViewController.
viewDidLoad{
[super viewDidLoad];
if([[NSUserDefaults standardUserDefaults] valueForKey:#"userId"]){
[self performSegueWithIdentifier:#"toProfile" sender: self];
}
I am in my first days of IOS app development, I am trying to build an authentication system for an already existent iOS App using Objective C.
The app's rootviewcontroller is a tabsview followed by navigationControllers.
What i've done so far:
1- creating the loginviewController class & designing it's UI in the storyboard
2- the same thing for the "registration" & "recover my password" classes
3- linking the root viewcontroller with the login page with a segue of type modal.
4- linking the login page with the registration & recover my password pages with segues of type push.
Now i don't know the steps that i should follow to make the login page appear to the user when he first enters the app & eventually store his state so he can access the app later without having to enter his credentials every time (unless he logs out).
Any help is greatly appreciated, thank you
I am available for any clarifications or eventually some screenshots/source code if needed.
Edit 1 : this is the content of my didFinishLaunchingWithOptions method in my appdelegate.m :
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
TabsViewController *controller = (TabsViewController *)self.window.rootViewController;
controller.managedObjectContext = self.managedObjectContext;
_observer = [[MyStoreObserver alloc] init];
[[SKPaymentQueue defaultQueue] addTransactionObserver:_observer];
//Create sub directories in doesn'n exist
NSString *documentsDirectory =[NSHomeDirectory() stringByAppendingPathComponent:#"Documents"];
NSString *pathToFile = [documentsDirectory stringByAppendingString:#"export"];
BOOL isDir = YES;
BOOL isFile = [[NSFileManager defaultManager] fileExistsAtPath:pathToFile isDirectory:&isDir];
if(isFile)
{
//it is a file, process it here how ever you like, check isDir to see if its a directory
}
else
{
[self createSubDirectories];
//not a file, this is an error, handle it!
}
return YES;
}
What should I add/change ??
Set your rootViewController programmatically by checking login status.
You can save your login status as a bool in NSUserDefault after Login & Logout.
After Login
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"LoginStatus"];
After Logout
[[NSUserDefaults standardUserDefaults] setBool:NO forKey:#"LoginStatus"];
Modify your appDelegate - didFinishLaunchingWithOptions: delegate method as follows
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:STORYBOARD_NAME bundle:nil];
//Check Login status
if (![[NSUserDefaults standardUserDefaults] boolForKey:#"LoginStatus"])
{
// user not logged in
LOGIN_VIEWCONTROLLER *rootviewcontroller=[storyboard instantiateViewControllerWithIdentifier:LOGIN_VIEWCONTROLLER_IDENTIFIER];
}
else
{
// user already logged in
TABBARCONTROLLER *rootviewcontroller=[storyboard instantiateViewControllerWithIdentifier:TABBARCONTROLLER_IDENTIFIER];
}
self.window.rootViewController = rootviewcontroller;
[self.window makeKeyAndVisible];
return YES;
}
Two Options:
1) You will need database (core data) to keep track of users log. It also may help you for offline login. You can create and set property 'isLoggedIn' to find last logged in user.
2) Create and save logged-in user details in file. Refer this file for next start up. If user is logged-out , then delete that file.
Update 1:
Create login View, push tabBar on succesful login , followed by navigation controller for further flow. Refer image :
Fixed it,
I actually changed the rootviewcontroller by adding this line of code in appdelegate
LoginViewController *controller = (LoginViewController *)self.window.rootViewController;
I also changed the entry of the application in my storyboard to be loginviewcontroller.
And I also added a method called prepareforSegue in my loginviewcontroller to pass as a parameter the managed objectcontext because it caused some errors in the beginning:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"toHome"]) {
TabsViewController_iPhone *tabsViewController;
tabsViewController=[segue destinationViewController];
tabsViewController.managedObjectContext=self.managedObjectContext;
}
}
Hope to have helped someone out there. If you need more explanations on how I fixed the problem I am available. Thank's for everyone.
Edit:
After taking some time to understand how objective C works, I came to the conclusion that my answer above was not complete, so this is actually what happend:
After the user logs in the first time, I store his user & password in NSUserDefaults.
When he logs out I set the NSUserDefaults user/pass variables to Null.
So now I added a test to the AppdDelegate' didFinishLaunchingWithOptions method that says:
if the user/pass variables on NSUserDefaults are set -> go to the main menu screen of the app
else -> go to the login screen of the app.
this is the code:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *username = [defaults stringForKey:#"username"];
NSString *password = [defaults stringForKey:#"password"];
if (username != nil && password != nil)
{
self.window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MyStoryboard" bundle:nil];
// determine the initial view controller here and instantiate it with
UIViewController *viewController = [storyboard instantiateViewControllerWithIdentifier:#"HEQMainMenuView"];
self.window.rootViewController = viewController;
[self.window makeKeyAndVisible];
}
else
{
self.window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MyStoryboard" bundle:nil];
// determine the initial view controller here and instantiate it with
UIViewController *viewController = [storyboard instantiateViewControllerWithIdentifier:#"HEQLoginView"];
self.window.rootViewController = viewController;
//viewController.man
[self.window makeKeyAndVisible];
}
}
Hope this helps :D
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!
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.