Store multiple key-value pair in NSUserDefaults - ios

I am building a simple login and registration in IOS (xcode 6.4). To save username and password i am using NSUserDefaults. But the problem is I Can't store multiple username and passwords since I am saving data to same key.What's the alternate method to implement it.I saw some similar questions on stackoverflow but couldn't understand the solution. So can anyone explain in easy way. HEre is my code:
//function for login pressed
- (IBAction)login:(UIButton *)sender
{
NSLog(#"%#,%#",userNameField.text,passwordField.text);
username = [[NSUserDefaults standardUserDefaults] objectForKey:#"username"];
password = [[NSUserDefaults standardUserDefaults] objectForKey:#"password"];
NSLog(#"%#,%#",username,password);
bool validUser = [username isEqualToString:userNameField.text];
bool validPassword = [password isEqualToString:passwordField.text];
if ([self checkWhetherFieldIsEmpty:userNameField.text :passwordField.text])
{
[self displayAlert:#"All Fileds are mandatory"];
}
else if(validUser && validPassword)
{
[self displayAlert:#"Successfull Login"] ;
}
else{
// NSLog(#"Invalid username or password");
[self displayAlert:#"Invalid login or password"];
}
}
//function when register button is pressed
- (IBAction)register:(UIButton *)sender
{
if([[[NSUserDefaults standardUserDefaults] objectForKey:#"username"] isEqualToString:userNameField.text])
{
[self displayAlert:#"User already exist"];
userNameField.text = #"";
passwordField.text = #"";
}
else
{
[[NSUserDefaults standardUserDefaults] setObject:userNameField.text forKey:#"username"];
[[NSUserDefaults standardUserDefaults] setObject:passwordField.text forKey:#"password"];
[[NSUserDefaults standardUserDefaults]synchronize];
NSLog(#"user Created successfully");
[self displayAlert:#"Registration Successfull"];
}
}

As pointed out by Simon, there are security issues storing usernames and passwords in NSUserDefaults. If you still want to do it however, it is quite simple.
NSUserDefaults is really not much more then a plist so you can store arbitrary complex structures created from NSArray and NSDictionary in NSUserDefaults. So you can do something like:
NSArray<NSDictionary*>* accounts = #[#{
#"username" : #"firstUsername",
#"password" : #"firstPassword"
}, #{
#"username" : #"secondUsername",
"password" : #"secondPassword"
}];
[[NSUserDefaults standardUserDefaults] setObject: accounts forKey:#"accounts"];
Note that you can't change one account only; if you need to change or add a new account, you should read the whole structure, convert the array and the dictionaries to mutable variants, and re-write it to the defaults all together.
UPDATE
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
NSMutableArray* mutableAccounts = [[defaults objectForKey:#"accounts"] mutableCopy];
// Add or remove accounts:
[mutableAccounts addObject:#{ #"username" : #"newAccount", #"password" : #"newPassword" }];
[mutableAccounts removeObjectAtIndex:0];
[defaults setObject:mutableAccounts forKey:#"accounts"];

You can simple save your password as object of key username, some think like:
- (IBAction)login:(UIButton *)sender {
NSLog(#"%#,%#",userNameField.text,passwordField.text);
NSString *password = userNameField.text.length > 0? [[NSUserDefaults standardUserDefaults] objectForKey:userNameField.text] : nil;
bool validUser = passwordField.text.length > 0 ? [passwordField.text isEqualToString:password] : NO;
if ([self checkWhetherFieldIsEmpty:userNameField.text :passwordField.text]) {
[self displayAlert:#"All Fileds are mandatory"];
}
else if(validUser){
[self displayAlert:#"Successfull Login"] ;
}
else{
// NSLog(#"Invalid username or password");
[self displayAlert:#"Invalid login or password"];
}
}
//function when register button is pressed
- (IBAction)register:(UIButton *)sender {
//TODO: need check userNameField passwordField is not nil here
if([[[NSUserDefaults standardUserDefaults] objectForKey:userNameField.text] length] > 0){
[self displayAlert:#"User already exist"];
userNameField.text = #"";
passwordField.text = #"";
}
else {
[[NSUserDefaults standardUserDefaults] setObject:passwordField.text forKey:userNameField.text];
[[NSUserDefaults standardUserDefaults]synchronize];
NSLog(#"user Created successfully");
[self displayAlert:#"Registration Successfull"];
}
}

Related

Crash interacting with NSUserDefaults and NSArray

I have an NSMutableArray in which I am adding objective and storing in user defaults, but while adding it is crashing.
if ([[NSUserDefaults standardUserDefaults] objectForKey:#"bssidObserverArray"]) {
bssidObserverArray = [[NSUserDefaults standardUserDefaults] objectForKey:#"bssidObserverArray"];
}
if (bssidObserverArray.count > 0) {
if (![bssidObserverArray containsObject:vendorID]) {
NSLog(#"bssidObserverArray %#",bssidObserverArray);
// In this line app is getting crashed
[bssidObserverArray addObject:vendorID];
[[NSUserDefaults standardUserDefaults] setObject:bssidObserverArray forKey:#"bssidObserverArray"];
}
}else{
[bssidObserverArray addObject:vendorID];
[[NSUserDefaults standardUserDefaults] setObject:bssidObserverArray forKey:#"bssidObserverArray"];
}
Any suggestions would be more helpful.
Assuming bssidObserverArray is NSMutable array then come the problem here .
if ([[NSUserDefaults standardUserDefaults] objectForKey:#"bssidObserverArray"]) {
bssidObserverArray = [[NSUserDefaults standardUserDefaults] objectForKey:#"bssidObserverArray"];
}
since NSUserdefaults returns immutable. you can do like this
if ([[NSUserDefaults standardUserDefaults] objectForKey:#"bssidObserverArray"]) {
NSArray *someArray = [[NSUserDefaults standardUserDefaults] objectForKey:#"bssidObserverArray"];
bssidObserverArray = [someArray mutableCopy];
}

Switch state not linking to Label

For some reason using NSUserDefaults to save the state of my switch and my label don't seem to be working. I can save the state of my switch and load it however unless i manually change the state of the switch the label will not change to on or off.
NSUserDefaults *standardDefaults = [NSUserDefaults standardUserDefaults];
self->switch1.on = ([[standardDefaults stringForKey:#"switchKey"]
isEqualToString:#"On"]) ? (YES) : (NO);
As you can see i added in label.text = #"OFF" when the switch is off but however it still doesn't change.
- (IBAction)switchChanged:(UISwitch *)sender {
NSUserDefaults *standardDefaults = [NSUserDefaults standardUserDefaults];
if (sender.on == 0) {
label.text = #"OFF";
[standardDefaults setObject:#"Off" forKey:#"switchKey"];
} else if (sender.on == 1) {
label.text = #"ON";
[standardDefaults setObject:#"On" forKey:#"switchKey"];
}
[standardDefaults synchronize];
}
Before i wanted to save the switch state i just used this.
-(IBAction) alarmSettings1{
if (switch1.on)
{ label.text = #"ON";}
else { label.text = #"OFF";}
}
I know I'm just doing something simple wrong but can't figure out what.
You should set your boolean like so:
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"switchKey"];
[[NSUserDefaults standardUserDefaults] synchronize];
So when you want to set the state of your switch, you would do:
BOOL switchState = [[NSUserDefaults standardUserDefaults] objectForKey:#"switchKey"];
self.switch1.on = switchState;
Also, in your IBAction method, read the state like so:
- (IBAction)switchChanged:(UISwitch *)sender {
label.text = sender.on ? #"ON" : #"OFF";
[[NSUserDefaults standardUserDefaults] setBool:sender.on forKey:#"switchKey"];
[[NSUserDefaults standardUserDefaults] synchronize];
}

Issue in NSUserDefaults LoginView with UISwitch

I'm unable to store my username and password in loginView when I enable rememberMe Switch.
Here is my code, Kindly help me!
- (void)viewDidLoad
{
if (rememberSwitch.on == YES){
self.usernameField.text = usernameField.text;
self.passwordField.text = passwordField.text ;
}else{
NSLog(#"switch is off");
self.usernameField.text = #"";
self.passwordField.text = #"";
}
}
- (IBAction)rememberMeTouched:(id)sender
{
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
if (rememberSwitch.on == YES) {
NSString *userString = usernameField.text;
[userDefaults setObject:userString forKey:#"userString"];
NSString *passwordString = passwordField.text;
[userDefaults setObject:passwordString forKey:#"passwordString"];
}
[userDefaults setObject:(rememberSwitch.on ? #"true" : #"false") forKey:#"isremember"];
[userDefaults synchronize];
}
You need to load the content from the NSUserDefault so your code should be like this:
if (rememberSwitch.on == YES){
self.usernameField.text = [userDefaults objectForKey:#"userString"];;
self.passwordField.text = [userDefaults objectForKey:#"passwordString"];;
}
Solved issue with code
NSString *username = [userDefaults objectForKey:#"userString"];
NSString *password = [userDefaults objectForKey:#"passwordString"];
usernameField.text = username;
passwordField.text = password;

How to use UISwitch with NSUserDefault

defaults = [NSUserDefaults standardUserDefaults];
NSLog(#"%#",[defaults objectForKey:#"firsttime"])
if([[defaults objectForKey:#"firsttime"]isEqualToString:#"YES"])
{
UISwitch *onoff = (UISwitch *) sender;
if(onoff.on)
{
NSLog(#"yes on1 facebookswitch");
facebookSwitch.on = YES;
[userDefault setValue:#"true" forKey:#"facebooknotify"];
NSLog(#"on");
if ([SLComposeViewController isAvailableForServiceType:SLServiceTypeFacebook]) {
[validate alertCommonWithoutMessage:NSLocalizedString(#"val_message",nil) :NSLocalizedString(#"val_facebook_login",nil) :#"OK"];
facebookSwitch.on = YES;
NSLog(#"yes on2 facebookswitch");
}
else {
NSLog(#"val_facebook_conf");
[validate alertCommonWithoutMessage:NSLocalizedString(#"val_message",nil) :NSLocalizedString(#"val_facebook_conf",nil) :#"OK"];
facebookSwitch.on = NO;
[userDefault setValue:#"false" forKey:#"facebooknotify"];
NSLog(#"yes off1 facebookswitch");
I'm using this method,but sumtimes the response is null.
Try this code:
// add this code in your switch touch event
- (IBAction)YourSwitch:(UISwitch*)sender
{
if (UISwitch.on)
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setBool:true forKey:#"Sound"];
[defaults synchronize];
}
else
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setBool:false forKey:#"Sound"];
[defaults synchronize];
}
}
// add this code in your viewDidload .
BOOL isSound= [[NSUserDefaults standardUserDefaults] objectForKey:#"Sound"];
if (isSound){
_ref_slider.on=TRUE;
} else {
_ref_slider.on=FALSE;
}
i hope this code is useful for you.
As to why it's not working, the most common problem is [userDefault synchronize]
Also, rather than using string boolean values, why not use:
[userDefault setBool:YES forKey:#"facebooknotify"];
and then access by
BOOL notified = [userDefault boolForKey:#"facebooknotify"];

GMSGeocoder - how to set response language

When using my app in a foreign country, the google GMSGeocoder is returning the response in local language automatically. how can I set it to always return the the response in English?
Im using GMS SDK 1.7 and my code is something like this:
GMSGeocoder *geoCoder = [[GMSGeocoder alloc] init];
[geoCoder reverseGeocodeCoordinate:self.cellLocation.coordinate completionHandler:^(GMSReverseGeocodeResponse *respones, NSError *err) {
if([respones firstResult]) {
GMSAddress* address = [respones firstResult];
NSString* fullAddress = [NSString stringWithFormat:#"%#, %#",address.thoroughfare, address.locality];
self.theTextField.text = fullAddress;
} else {
self.theTextField.text = #"";
}
}];
Using a GMSGeocoder category can solve this issue, inspired by #DaNLtR
After that , It can set geocoder result as English .
#implementation GMSGeocoder (Load)
+(void)load {
[[self class] setUserLanguage:#"en-CN"];// set your wanted language.
NSLog(#"GMSGeocoder + load!");
}
- (void)dealloc {
[[self class] resetSystemLanguage];
NSLog(#"GMSGeocoder + dealloc!");
}
+ (void)setUserLanguage:(NSString *)userLanguage
{
if (!userLanguage.length) {
[[self class] resetSystemLanguage];
return;
}
[[NSUserDefaults standardUserDefaults] setValue:userLanguage forKey:#"UserLanguage"];
[[NSUserDefaults standardUserDefaults] setValue:#[userLanguage] forKey:#"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
+ (void)resetSystemLanguage
{
[[NSUserDefaults standardUserDefaults] removeObjectForKey:#"UserLanguage"];
[[NSUserDefaults standardUserDefaults] setValue:nil forKey:#"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
#end
Why should in category?
A:I tested setLanguage: before GMSGeocoder reverseGeocodeCoordinate method, it can't affect geocoder result. After I saw DaNLtR's answer , I think we can setLanguge in load method.
Why should reset language?
A:Avoide affect other module or framework .
Just change it to your language parameters
int main(int argc, char * argv[])
{
#autoreleasepool {
//For Google Maps hebrew response
//[[NSUserDefaults standardUserDefaults] setObject:#[#"en"] forKey:#"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] setObject:#[#"he",#"he-IL"] forKey:#"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize];
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}

Resources