How to save password in UserDefault using the NSUserDefault? - iphone

I want to save password when user select remember me checkbox. I have code like this:is this correct?
In Appdelegate.m
#property(strong,nonatomic)NSString *savedno;
in .m file
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
// Override point for customization after application launch.
self.viewController = [[[ViewController alloc] initWithNibName:#"ViewController" bundle:nil] autorelease];
self.navcontrol =[[UINavigationController alloc]initWithRootViewController:self.viewController ];
self.window.rootViewController = self.navcontrol;
[self.window makeKeyAndVisible];
self.savedno=[[NSUserDefaults standardUserDefaults]objectForKey:#"pass"];
if(savedno==nil)
{
NSDictionary *saveDict=[NSDictionary dictionaryWithObject:savedno forKey:#"pass"];
[[NSUserDefaults standardUserDefaults]registerDefaults:saveDict];
}
return YES;
}
- (void)applicationWillTerminate:(UIApplication *)application
{
/*
Called when the application is about to terminate.
Save data if appropriate.
See also applicationDidEnterBackground:.
*/
NSUserDefaults *userdefault=[NSUserDefaults standardUserDefaults];
[userdefault setObject:savedno forKey:#"pass"];
}
//ViewDelegate.m file
//event of checkbox
-(IBAction)check:(id)sender
{
if (checkboxSelected == 0)
{
[checkboxButton setSelected:YES];
[checkboxButton setImage:[UIImage imageNamed:#"checkbox-checked.png"]forState:UIControlStateNormal];
// userdefault=[NSUserDefaults standardUserDefaults];
// [userdefault setObject:user.text forKey:#"user"];
// [userdefault setObject:pass.text forKey:#"pass"];
self.callno=pass.text;
pass.text=self.callno;
AppDelegate *appdelegate=[[UIApplication sharedApplication]delegate];
appdelegate.savedno=self.callno;
NSLog(#"Data saved");
checkboxSelected = 1;
}
else
{
[checkboxButton setSelected:NO];
[checkboxButton setImage:[UIImage imageNamed:#"checkbox.png"]forState:UIControlStateNormal];
user.text=#"";
pass.text=#"";
checkboxSelected = 0;
}
}
- (void)viewDidLoad
{
user.clearButtonMode=UITextFieldViewModeWhileEditing;
AppDelegate *appdel=[[UIApplication sharedApplication]delegate];
if([user.text isEqualToString:#"bhoomi"])
{
pass.text=appdel.savedno;
}
[super viewDidLoad];
checkboxSelected = 0;
// Do any additional setup after loading the view, typically from a nib.
}
`

Don't. NSUserDefaults isn't the place for confidential information like passwords. Instead, use the KeyChain.

You should use the keychain to store information like passwords.
Have a look at SFHFKeychainUtils, it will allow to easily use the keychain in your app. It provides two methods: storeUserName:andPassword: and getPasswordForUsername that will make it a snap, and secure!

To save to user defaults do the following
[[NSUserDefaults standardUserDefaults] setValue:#"YourPassword" forKey:#"passowrd"];
//then call
[[NSUserDefaults standardUserDefaults] synchronize];
To get it back
NSString *password = [[NSUserDefaults standardUserDefaults] valueForKey:#"password"];

after setting value to NSUserDefaults you have to synchronize once to get it saved. Use following statement to do so.
[[NSUserDefaults standardUserDefaults] synchronize];
Hope this helps.
EDIT:
It is wise to store credentials into keychain rather than NSUserDefaults.
Use this KeyChain Helper class for the same

use this code...
NSUserDefault *userDefault = [NSUserDefaults standardUserDefaults];
[userDefault setValue:pass_str forKey:#"pass"];
[userDefault synchronize];
may this will help you...

Related

Opening app from last opened UIViewController

I need my app to remember which was the last UIViewController opened so when the app is loaded out of memory, I substitute a rootViewController property in the AppDelegate with one saved in NSUserDefaults:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UIWindow *window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window = window;
frontViewController = [[SGLoginScreenViewController alloc] init];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:frontViewController];
self.window.rootViewController = navController;
[self.window makeKeyAndVisible];
return YES;
}
What I want to do is to put some code in the ViewDidLoad method of each ViewController and remember its name in NSUserDefaults to later use it in didFinishLaunchingWithOptions, something like this:
[[NSUserDefaults standardUserDefaults] setObject:self forKey:#"currentViewController"];
[[NSUserDefaults standardUserDefaults] synchronize];
The problem is, however, that XCode is giving me this warning:
*** -[NSUserDefaults setObject:forKey:]: Attempt to insert non-property value '<SGMainScreenFirstTimeViewController: 0x8e1fea0>' of class 'SGMainScreenFirstTimeViewController'. Note that dictionaries and arrays in property lists must also contain only property values.
Any ideas on how to implement this whole thing right? Thanks in advance
You can only save in user defaults objects that can conform to the Key-Value coding (NSString, NSnumber, etc). Converting class to string and recreating class knowing class name would be the way to go for what you wish to achieve.
This would be a good approach for saving in NSUserDefaults
[[NSUserDefaults standardUserDefaults] setObject:NSStringFromClass([self class]); forKey:#"currentViewController"];
[[NSUserDefaults standardUserDefaults] synchronize];
And for loading back you recreate the class based on the saved string, as below:
NSString *savedClassName = [[NSUserDefaults standardUserDefaults] objectForKey:#"currentViewController"];
UIViewController *controller = [(UIViewController *)NSClassFromString(savedClassName) alloc] init];
NSUSerDefaults is basically to store default values... not big objects ( list of items that can be saved includes (NSString,NSData,NSDictionary,NSArray,NSNumber) ..keep that in mind next time.
better way to do the functionality.
[[NSUserDefaults standardUserDefaults] setObject:#"Second View" forKey:#"currentViewController"];
[[NSUserDefaults standardUserDefaults] synchronize];
and then on app Load
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
if ([[[NSUserDefaults standardUserDefaults] objectForKey:#"currentViewController"] isEqualToString:#"Second View"])
{
//your code/logic
According to the documentation:
The value parameter can be only property list objects: NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary. For NSArray and NSDictionary objects, their contents must be property list objects.
So you can save name of your view controller and restore it on start, knowing its name
First thing is you can't save mutable values in NSUserDefaults. just check the psudocode following :
[[NSUserDefaults standardUserDefaults] setObject:#"nibnameofcurrentViewController" forKey:#"currentViewController"];
[[NSUserDefaults standardUserDefaults] synchronize];
when your app launch again then do following:
UIViewController *controller=[[UIViewController alloc]initWithNibName:[[NSUserDefault standerdDefault]objectForkey:#"currentViewController"] bundle:nil];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:frontViewController];
self.window.rootViewController = navController;

iphone app delegate with logic + facebook connect?

i'm really stuck on this one so please help!
I'm writing an app that implements facebook connect so when the app starts, I need it to check to see if it has a valid facebook access token, AND also check if their appKey that i provide is still valid (i don't want more than 1 account logged in at a time). so what needs to happen is..
App starts -> get facebook/my access key/token from NSUserDefaults -> send my appkey to a server to make sure it's still valid -> if valid then show my tableviewcontroller.
if it fails anywhere else(facebook access token isn't valid, or their appkey for my app isn't valid), then they will be taken to a View with the facebook connect button. after they login from there, they will be shown the tableviewcontroller
I don't know how to structure my app delegate and view controllers for this to work. From what I know about the facebook connect, most of the stuff has to happen in the delegate because facebook's application:handleOpenUrl: and fbDidLogin methods have to be called in the app delegate but if i do a
self.window.rootViewController = self.tableController
or
self.window.rootViewController = self.loginButtonViewController
before that, then i won't have access to these methods
Do i need to put in a delegate or something from the view controller back to the app delegate? i have no clue..
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
facebook = [[Facebook alloc] initWithAppId:#"MY_APP_ID"];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if ([defaults objectForKey:#"FBAccessTokenKey"]
&& [defaults objectForKey:#"FBExpirationDateKey"]) {
facebook.accessToken = [defaults objectForKey:#"FBAccessTokenKey"];
facebook.expirationDate = [defaults objectForKey:#"FBExpirationDateKey"];
}
NSString *myKey;
if ([defaults stringForKey:#"myKey"]) {
myKey= [[NSString alloc] initWithString:[defaults stringForKey:#"myKey"]];
}
else{
myKey = [[NSString alloc] initWithString:#""];
}
//SEND THE KEY + FBID TO SERVER
if ([facebook isSessionValid] /*&& [response==OK]*/) {
self.window.rootViewController = self.navController;
//delegate data to EventsTableController
}
else{
self.window.rootViewController = self.loginController;
}
[self.window makeKeyAndVisible];
return YES;
}
- (void)fbDidLogin {
NSLog(#"did login");
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:[facebook accessToken] forKey:#"FBAccessTokenKey"];
[defaults setObject:[facebook expirationDate] forKey:#"FBExpirationDateKey"];
[defaults synchronize];
NSString *myKey;
[facebook requestWithGraphPath:#"me" andDelegate:self];
if ([defaults stringForKey:#"myKey"]) {
myKey= [[NSString alloc] initWithString:[defaults stringForKey:#"myKey"]];;
}
else{
myKey= [[NSString alloc] initWithString:#""];
}
//NSString *validKey = [[NSString alloc] initWithString:#"OK"];
//Send myKey and validKey to server
//server will do its thang and send data
[self.window addSubview:self.navController.view];
[self.window makeKeyAndVisible];
}
thanks in advance
What means myKey?
In facebook.h, the method isSessionValid uses only two variables. (accessToken, expirationDate)
- (BOOL)isSessionValid {
return (self.accessToken != nil && self.expirationDate != nil
&& NSOrderedDescending == [self.expirationDate compare:[NSDate date]]);
}
You should have moved above code to RootViewController.m not AppDelegate.m
Because MainWindow.xib can recognize only one RootView.
(In your case, you wanted to have more RootView, navController, loginController)
See this Page
So, I suggest that you move your authorization code to RootViewController.m
(etc. viewDidLoad or viewWillAppear methods)
Next, in RootViewController, try to change your view according to whether session is valid or not.
And try Again! It will work!

UISwitch Not Responding To NSUserDefault Changes

I have a UISwitch in my app along with one in my settings bundle with the same functionality. The UISwitch in my app however is not saving its settings properly. Can anyone see anything wrong with the code?
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Set the application defaults
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSDictionary *appDefaults = [NSDictionary dictionaryWithObject:#"No" forKey:#"isKgs"];
[defaults registerDefaults:appDefaults];
[defaults synchronize];
}
- (void)switchChanged
{
[[NSUserDefaults standardUserDefaults] setBool:unitSwitch.selected forKey:#"isKgs"];
[[NSUserDefaults standardUserDefaults] synchronize];
NSLog(#"SwitchGhanged:");
}
-(void)cellForRowAtIndexPath
{
[unitSwitch addTarget:self action:#selector(switchChanged) forControlEvents:UIControlEventValueChanged];
if ([[NSUserDefaults standardUserDefaults] boolForKey:#"isKgs"])
{
[unitSwitch setOn:YES animated:NO];
}
}
And here is the settings bundle
[[NSUserDefaults standardUserDefaults] setBool:unitSwitch.on forKey:#"isKgs"];
Use the on property for setting.
Try using on on the UISwitch:
[[NSUserDefaults standardUserDefaults] setBool:unitSwitch.on forKey:#"isKgs"];
EDIT: No need to test as unitSwitch.on is already BOOLEAN, you can assign it directly.

How To Connect NSUserDefaults To UISwitch?

So I have setup my settings bundle which works in the iPhone's settings app. I want to add one of the settings within my own app. I know I can use InAppSettings framework, but I just want to add one settings, not all of them, and I already have an page ready that I want to add this settings option to.
So I have replicated the cell with UISwitch in my app which looks the same as the settings one. My question is, how can I now connect this UISwitch to my NSUserDefaults so it functions as a settings UISwitch?
In my appDelegate, I have:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSDictionary *appDefaults = [NSDictionary dictionaryWithObject:#"No" forKey:#"isKgs"];
[defaults registerDefaults:appDefaults];
[defaults synchronize];
Edit - All related code:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setBool:NO forKey: #"isKgs"];
[defaults synchronize];
}
The cell inside the app where I want the UISwitch to be
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UISwitch *switchView = [[UISwitch alloc] initWithFrame:CGRectZero];
cell.accessoryView = switchView;
[switchView addTarget:self action:#selector(switchChanged:) forControlEvents:UIControlEventValueChanged];
[switchView setOn:[[NSUserDefaults standardUserDefaults] boolForKey:#"isKgs"] animated:NO];
[switchView release];
}
And the settings bundle where I have the same UISwitch that can be acceded through iPhone settings app:
Edit 2:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if (nil == [defaults objectForKey:#"isKgs"])
{
[defaults setBool:NO forKey: #"isKgs"];
}
else
{
}
[defaults synchronize];
It's easier to use a boolean variable if you want to use a UISwitch. In the app delegate, set the default value for the settings, if not existed:
// set the default settings
NSString *testValue = [[NSUserDefaults standardUserDefaults] stringForKey:#"testSwitch"];
if (!testValue) {
// since no default values have been set, create them here
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"testSwitch"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
And then create use the value from the NSUserDefaults settings to turn on the switch if needed:
UISwitch* testSwitch = [[[UISwitch alloc] init] autorelease];
if ([[NSUserDefaults standardUserDefaults] boolForKey:#"testSwitch"]) {
[testSwitch setOn:YES animated:NO];
}
You should head aporat's suggestion and use a BOOL instead. However, if you are insistent on using a string as in your question, then you will have to do this:
if ([[[NSUserDefaults standardUserDefaults] objectForKey:#"isKgs"] isEqualToString:#"No") {
[switch setOn:NO animated:NO];
}
However, if you use a BOOL, you can set the switch in one simple line:
[switch setOn:[[NSUserDefaults standardUserDefaults] boolForKey:#"isKgs"] animated:NO];
This means that you must go back and set up the defaults like this:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setBool:NO forKey#"isKgs"];
[defaults synchronize];
At some point in your code you are going to have to check the switch state and write it back to userDefaults:
[[NSUserDefaults standardUserDefaults] setBool:[switch on] forKey:#"isKgsk"];
[defaults synchronize];
you can write the changes back to userDefaults in your switchChanged: function.
Also, if you always set your key to NO in didFinishLaunchingWithOptions: then it will never reflect changes made in the settings app, it will always be NO.... this is probably not what you want.

Best way to check if an iPhone app is running for the first time

I want to check if my iPhone app is running for the first time. I can create a file in the documents folder and check that file to see if this is the first time the app is running, but I wanted to know if there is a better way to do this.
I like to use NSUserDefaults to store an indication of the the first run.
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if (![defaults objectForKey:#"firstRun"])
[defaults setObject:[NSDate date] forKey:#"firstRun"];
[[NSUserDefaults standardUserDefaults] synchronize];
You can then test for it later...
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if([defaults objectForKey:#"firstRun"])
{
// do something or not...
}
Ok what confuses the hell out of me about User Defaults.
WHERE are they stored?
you dont care it varies per iOS/Mac.
you just getVALUE by KEY
setVALUE by KEY + synchronize
iOS/Mac does the rest.
This is the common use case:
Checking for the existence of a value e.g firstRun.
The first time it will NOT EXIST so usually followed by setting the value.
2nd Run
- on next loop it does exist and other use case/else stmt is triggered
---- .h
#interface MyAppDelegate : UIResponder <UIApplicationDelegate>
//flag to denote if this is first time the app is run
#property(nonatomic) BOOL firstRun;
------ .m
#implementation MyAppDelegate
#synthesize firstRun = _firstRun;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//==============
//Check to see if this is first time app is run by checking flag we set in the defaults
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if (![defaults objectForKey:#"firstRun"]){
//flag doesnt exist then this IS the first run
self.firstRun = TRUE;
//store the flag so it exists the next time the app starts
[defaults setObject:[NSDate date] forKey:#"firstRun"];
}else{
//flag does exist so this ISNT the first run
self.firstRun = FALSE;
}
//call synchronize to save default - where its saved is managed by iOS - varies by device and iOS/Mac
[[NSUserDefaults standardUserDefaults] synchronize];
//TO TEST: delete the app on the device/simulator
//run it - should be the first run
//close it - make sure you kill it and its not just in the background else didFinishLaunchingWithOptions wont be called
//just applicationDidBecomeActive
//2nd run it should self.firstRun = FALSE;
//=============
//NOTE IMPORTANT IF YOURE ROOTVIEWCONTROLLER checks appDelegate.firstRun then make sure you do the check above BEFORE setting self.window.rootViewController here
self.window.rootViewController = self.navController;
[self.window makeKeyAndVisible];
return YES;
}
---- USING THE FLAG
MyAppDelegate *appDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
if (appDelegate.firstRun){
NSLog(#"IS FIRST RUN - Do something: e.g. set up password");
}else {
NSLog(#"FPMyMusicScreenViewController: IS NOT FIRST RUN - Prompt for password");
}
The examples above confused me a bit as they show how to check for it the first time but then mention how to 'check for it later' in the same comment.
The problem is when we find it doesnt exist we immediately create it and synchronize.
So checking for it late actually mean when you RESTART THE APP not in same run as first run.
In your app delegate register a default value:
NSDictionary *defaultsDict =
[[NSDictionary alloc] initWithObjectsAndKeys:[NSNumber numberWithBool:YES], #"FirstLaunch", nil];
[[NSUserDefaults standardUserDefaults] registerDefaults:defaultsDict];
[defaultsDict release];
Then where you want to check it:
NSUserDefaults *sharedDefaults = [NSUserDefaults standardUserDefaults];
if ([sharedDefaults boolForKey:#"FirstLaunch"]) {
//Do the stuff you want to do on first launch
[sharedDefaults setBool:NO forKey:#"FirstLaunch"];
[sharedDefaults synchronize];
}
You can implement it with the static method below. I think it's better since you can call this method as many times as you like, unlike the other solutions. enjoy: (Keep in mind that it's not thread-safe)
+ (BOOL)isFirstTime{
static BOOL flag=NO;
static BOOL result;
if(!flag){
if ([[NSUserDefaults standardUserDefaults] boolForKey:#"hasLaunchedOnce"])
{
result=NO;
} else
{
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"hasLaunchedOnce"];
[[NSUserDefaults standardUserDefaults] synchronize];
result=YES;
}
flag=YES;
}
return result;
}
You can use a custom category method isFirstLaunch with UIViewController+FirstLaunch.
- (BOOL)isFirstLaunch
{
if ([[NSUserDefaults standardUserDefaults] boolForKey:#"kFirstLaunch"]) {
return YES;
}
else {
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"kFirstLaunch"];
[[NSUserDefaults standardUserDefaults] synchronize];
return NO;
}
}
And when you need to use it in controller
BOOL launched = [self isFirstLaunch];
if (launched) {
//if launched
}
else {
//if not launched
}
Use NSUserDefaults. If the sharedDefault has a key for your app, its run before. Of course, you'll have to have the app create at least one default entry the first time the app runs.
Swift:
var isFirstLaunch: Bool {
get {
if (NSUserDefaults.standardUserDefaults().objectForKey("firstLaunchDate") == nil) {
NSUserDefaults.standardUserDefaults().setObject(NSDate(), forKey: "firstLaunchDate")
NSUserDefaults.standardUserDefaults().synchronize()
return true
}
return false
}
}
Another tip:
When using NSUserDefaults, these settings will be wiped if the app is ever deleted. If for some reason you require these settings to still hang around, you can store them in the Keychain.