How to create a modal view , for application launch in iOS? - ios

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.

Related

Show a view just once in whole life cycle of an App

I am working on a shopping app and on app launch, it shows signup view and once skip button is clicked it navigates to home view. I want to show signup view just once in whole life time of an app.
Adding here the code I used to show walkthrough screen only once in the entire application lifecycle. This can be useful to you.
// show walkthough for first time only (first time the app launches after download).
bool shownFlag = [[NSUserDefaults standardUserDefaults] boolForKey:#"walkthroughShownOnce"];
if(!shownFlag){
[[NSUserDefaults standardUserDefaults] setBool:TRUE forKey:#"walkthroughShownOnce"];
[[NSUserDefaults standardUserDefaults] synchronize];
WalkThroughViewController *vc=[[UIStoryboard storyboardWithName:#"Main" bundle:nil] instantiateViewControllerWithIdentifier:#"WalkThroughViewController"];
[self.window makeKeyAndVisible];
[self.window setRootViewController:vc];
}else{
//if not walkthough go and check other task
}

IOS & objective C development - how to make the login page appear to the user?

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

UIViewController did not deallocate itself

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.

Change Initial View Controller for First Launch

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!

Programmatically setup/activate Segue

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.

Resources