Crash Only in iOS 5.1 [duplicate] - iphone

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Why does clearing NSUserDefaults cause EXC_CRASH later when creating a UIWebView?
**Hi all, I have a FAQ screen in the app and this is webview, this webpage has as "Email Me" link in it. When clicked on this this navigates to Mail Composer. But app still runs in the background. Now click back the minimized app and click the same FAQ link, app crashes. This only happens in iOS 5.1 . Below are the logs which are received :
-[__NSCFDictionary setObject:forKey:]: attempt to insert nil value (key: WebKitLocalStorageDatabasePathPreferenceKey)
I have used the below code in "APPDelegate" file
NSDictionary *settings = [[NSUserDefaults standardUserDefaults] dictionaryRepresentation];
NSArray *keys = [settings allKeys];
for (int i=0; i<[keys count]; i++)
{
NSString *key = [keys objectAtIndex:i];
[[NSUserDefaults standardUserDefaults] removeObjectForKey:key];
}
[[NSUserDefaults standardUserDefaults] synchronize];

This crash is not because of version change. The crash log clearly says you are trying to insert nil value in Dictionary and that's why it is crashing :
for (int i=0; i<[keys count]; i++)
{
NSString *key = [keys objectAtIndex:i];
if (key != nil)
[[NSUserDefaults standardUserDefaults] removeObjectForKey:key];
}
Try the above code and check.

Try the below code. Remove anything formNSUserDefaults in this way
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSDictionary *userDefaultsDictionary = [userDefaults dictionaryRepresentation];
NSString *strWebDatabaseDirectory = [userDefaultsDictionary objectForKey:#"WebDatabaseDirectory"];
NSString *strWebKitLocalStorageDatabasePathPreferenceKey = [userDefaultsDictionary objectForKey:#"WebKitLocalStorageDatabasePathPreferenceKey"];
NSString *appDomain = [[NSBundle mainBundle] bundleIdentifier];
[[NSUserDefaults standardUserDefaults] removePersistentDomainForName:appDomain];
[userDefaults removePersistentDomainForName:[[NSBundle mainBundle] bundleIdentifier]];
if (strWebDatabaseDirectory) {
[userDefaults setObject:strWebDatabaseDirectory forKey:#"WebDatabaseDirectory"];}
if (strWebKitLocalStorageDatabasePathPreferenceKey) {
[userDefaults setObject:strWebKitLocalStorageDatabasePathPreferenceKey forKey:#"WebKitLocalStorageDatabasePathPreferenceKey"];}
[userDefaults synchronize];
Hope it may help you.

Related

How to remove user defaults [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How can I reset the NSUserDefaults data in the iPhone simulator?
In my project i am saving some values in NSUserdefaults with different keys.And i have reset button in my app when i click that button values stored in user defaults should remove.Is there any way to delete those values without keys,and is addSuitedNamed: and removeSuitedName can use in this scenario.
NSUserDefaults * myNSUserDefaults = [NSUserDefaults standardUserDefaults];
NSDictionary * dict = [myNSUserDefaults dictionaryRepresentation];
for (id key in dict) {
//heck the keys if u need
[myNSUserDefaults removeObjectForKey:key];
}
[myNSUserDefaults synchronize];
or
[NSUserDefaults resetStandardUserDefaults];
[NSUserDefaults standardUserDefaults];
With a selector being called on a button click you can achieve the same using
- (IBAction)btnResetUserDefaultsPressed:(id)sender {
NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
NSDictionary* dictUserDefaults = [userDefaults dictionaryRepresentation];
for (id akey in dictUserDefaults) {
[userDefaults removeObjectForKey:akey];
}
[userDefaults synchronize];
}
For the second part of your question asked , You would certainly find this useful.
You can reset the values of NSUserDefault using resetStandardUserDefaults.
Check this code:
[NSUserDefaults resetStandardUserDefaults];
[NSUserDefaults standardUserDefaults];
Also you can:
NSString *appDomain = [[NSBundle mainBundle] bundleIdentifier];
[[NSUserDefaults standardUserDefaults] removePersistentDomainForName:appDomain];
Or you can use:
NSUSerDefaults *default = [NSUserDefaults standardUserDefaults];
NSDictionary *dictionary = [default dictionaryRepresentation];
for (NSString *key in [dictionary allKeys])
{
[default removeObjectForKey:key];
}
[default synchronize];

iphone : Settings.bundle returns null value

I was using xCode 3.2 and then moved to xCode 4.2 and getting some values from Settings.bundle ... it was working fine.
Mean while I need to edit some values in Settings.bundle but The Root.plist file was not showing so I follow the below procedure but did not make any change in file.
1) Click on the Settings.Bundle file, go over to the utilities window,
and look in the File Inspector.
2) Using the drop-down, change the file type to 'Application Bundle'
After that I could see Root.plist but now could not get its values in application. Actually getting Null instead of value.
Below is code and image of Settings.bundle
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
host = [defaults stringForKey:#"meter_preference"];
if(host == nil)
{
host = #"10.20.20.1";
DDLogError(#"Meter host is nil from NSUserDefaults, defaulting to %#", host);
}
I got the solution, just call the below code in applicationDidFinishLaunchingWithOptions to initialize User defaults. and it works
Replace somePropertyYouExpect in first line with property you stored in User Defaults.
if (![[NSUserDefaults standardUserDefaults] objectForKey:#"somePropertyYouExpect"]) {
NSString *mainBundlePath = [[NSBundle mainBundle] bundlePath];
NSString *settingsPropertyListPath = [mainBundlePath
stringByAppendingPathComponent:#"Settings.bundle/Root.plist"];
NSDictionary *settingsPropertyList = [NSDictionary
dictionaryWithContentsOfFile:settingsPropertyListPath];
NSMutableArray *preferenceArray = [settingsPropertyList objectForKey:#"PreferenceSpecifiers"];
NSMutableDictionary *registerableDictionary = [NSMutableDictionary dictionary];
for (int i = 0; i < [preferenceArray count]; i++) {
NSString *key = [[preferenceArray objectAtIndex:i] objectForKey:#"Key"];
if (key) {
id value = [[preferenceArray objectAtIndex:i] objectForKey:#"DefaultValue"];
[registerableDictionary setObject:value forKey:key];
}
}
[[NSUserDefaults standardUserDefaults] registerDefaults:registerableDictionary];
[[NSUserDefaults standardUserDefaults] synchronize];
}
From your code , try this thinks..
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
host = [defaults stringForKey:#"meter_preference"];
if(!host == nil)
{
host = #"10.20.20.1";
DDLogError(#"Meter host is nil from NSUserDefaults, defaulting to %#", host);
}
OR
Review this link may be helped you...
iPhone - reading Setting.bundle returns wrong values
NSUserDefaults Settings Bundle Plist

How to save User Name and Password in NSUserDefault?

I need to save User Name and Password in NSUserDefault. I am planning to place a round rect button in IB. On pressing of which the User name and Password would be saved in NSUserDefault, so that when user kills the application and tries to login again after some time, they do not need to enter their login details again.
Any help would be highly appreciated.
Thanks and best regards,
PC
For Saving Username and Password I will personally suggest to use Keychain as they are more safer than NSUserDefault in terms of security since Keychain stores data in encrypted form while NSUserDefault stores as plain text. If you still want to use NSUserDefault Here's the way
FOR SAVING
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
// saving an NSString
[prefs setObject:txtUsername.text forKey:#"userName"];
[prefs setObject:txtPassword.text forKey:#"password"];
[prefs synchronize];
FOR RETRIEVING
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
// getting an NSString
NSString *savedUsername = [prefs stringForKey:#"userName"];
NSString *savedPassword = [prefs stringForKey:#"password"];
Do not store plaintext passwords in user defaults, even if they are unimportant.
Use Keychain Services. The Generic Keychain Sample provides sample KeychainWrapper class, that can be used for reading and writing data into keychain with exactly the same setObject:forKey: interface as NSUserDefaults uses.
To Save:
[[NSUserDefaults standardUserDefaults] setValue:_Username forKey:#"Username"];
[[NSUserDefaults standardUserDefaults] setValue:_password forKey:#"password"];
[[NSUserDefaults standardUserDefaults] synchronize];
To Read:
NSString * _UserName = [[NSUserDefaults standardUserDefaults] stringForKey:#"Username"];
NSString * _password = [[NSUserDefaults standardUserDefaults] stringForKey:#"password"];
First off, I would not store the password in NSUserDefaults. I would rather use the keychain.
This is how you can save the username in NSUserDefaults:
NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];
[standardUserDefaults setObject:myString forKey:#"username"];
NSString* username = [standardUserDefaults objectForKey:#"username"];
On the other hand, an easy way to use the keychain is by using the SSKeychain class by Sam Soffes; in this case you would just say:
NSString* password = [SSKeychain passwordForService:#"YOUSERVICENAMEHERE" account:username];
[SSKeychain setPassword:password forService:#"YOUSERVICENAMEHERE" account:username];
You can store your credentials like this:
-(void)saveToUserDefaults:(NSString*)stringUserName pswd:(NSString*)strPassword
{
NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];
if (standardUserDefaults) {
[standardUserDefaults setObject:stringUserName forKey:#"UserName"];
[standardUserDefaults setObject:strPassword forKey:#"Password"];
[standardUserDefaults synchronize];
}
}
And you can retrive them like this:
-(NSArray*)retrieveFromUserDefaults
{
NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];
if (standardUserDefaults) {
NSString *userName = (NSString*)[standardUserDefaults objectForKey:#"UserName"];
NSString *password = (NSString*)[standardUserDefaults objectForKey:#"Password"];
}
NSArray* credentials = [NSArray arrayWithObjects:userName, password, nil];
return credentials;
}
Cannot set NSUserDefaults field
Posted my code from link to stay assured that answer is still useful to community even if the above mentioned post is removed or deleted in future.
Code:
You can try this code. I am very sure that it will work for you.
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *uid=#"1";
[defaults setObject:uid forKey:#"init_val"];
[defaults synchronize];
For Retrieving Data You Should Use The Following Code :
NSString *initVal=[[NSUserDefaults standardUserDefaults] valueForKey:#"init_val"];
OR
NSString *initVal=[[NSUserDefaults standardUserDefaults] objectForKey:#"init_val"];
EDIT:
If still it gives nil, then you can use the following code:
NSString *initVal=[NSString stringWithFormat:#"%#",[[NSUserDefaults standardUserDefaults] valueForKey:#"init_val"]];
OR
NSString *initVal=[NSString stringWithFormat:#"%#",[[NSUserDefaults standardUserDefaults] objectForKey:#"init_val"]];
In the above link, you will find my answer and replace "init_val" in my code there with your "username" and "password" as keys
Hope this helps you.
Good Answers are already given But here is a clean way of Saving/Loading/Deleting User Credentials in the keychain. Consider this, you can create a separate class and include the following code:
.h
#import <Foundation/Foundation.h>
#interface KeychainUserPass : NSObject
+ (void)save:(NSString *)service data:(id)data;
+ (id)load:(NSString *)service;
+ (void)delete:(NSString *)service;
#end
.m
#import "KeychainUserPass.h"
#implementation KeychainUserPass
+ (NSMutableDictionary *)getKeychainQuery:(NSString *)service {
return [NSMutableDictionary dictionaryWithObjectsAndKeys:
(__bridge id)kSecClassGenericPassword, (__bridge id)kSecClass,
service, (__bridge id)kSecAttrService,
service, (__bridge id)kSecAttrAccount,
(__bridge id)kSecAttrAccessibleAfterFirstUnlock, (__bridge id)kSecAttrAccessible,
nil];
}
+ (void)save:(NSString *)service data:(id)data {
NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
SecItemDelete((__bridge CFDictionaryRef)keychainQuery);
[keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:data] forKey:(__bridge id)kSecValueData];
SecItemAdd((__bridge CFDictionaryRef)keychainQuery, NULL);
}
+ (id)load:(NSString *)service {
id ret = nil;
NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
[keychainQuery setObject:(id)kCFBooleanTrue forKey:(__bridge id)kSecReturnData];
[keychainQuery setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit];
CFDataRef keyData = NULL;
if (SecItemCopyMatching((__bridge CFDictionaryRef)keychainQuery, (CFTypeRef *)&keyData) == noErr) {
#try {
ret = [NSKeyedUnarchiver unarchiveObjectWithData:(__bridge NSData *)keyData];
}
#catch (NSException *e) {
NSLog(#"Unarchive of %# failed: %#", service, e);
}
#finally {}
}
if (keyData) CFRelease(keyData);
return ret;
}
+ (void)delete:(NSString *)service {
NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
SecItemDelete((__bridge CFDictionaryRef)keychainQuery);
}
#end

Settings Bundle values not being linked correctly on iPhone

I have an issue I've been struggling with for the last few days. I have a settings bundle, root.plist, which holds some user preferences. In it are three multivalue menu items. One returns a boolean, the other two return numbers.
When I call [[NSUserDefaults standardUserDefaults] dictionaryRepresentation] and examine it in the console, only the first item in the property list shows up with its value. The other two are conspicuously absent. As a result, when I try to retrieve those values, I get zero.
What's weirder is that the settings bundle looks correct in the Settings app on the iPhone. The only thing not working is that the values are not getting passed. As far as my app is concerned, the other two multivalue menu items don't even exist.
Any suggestions are greatly appreciated.
I've used this block of code, multiple times, in applicationDidFinishLaunchingWithOptions to initialize my user defaults.
if (![[NSUserDefaults standardUserDefaults] objectForKey:#"somePropertyYouExpect"]) {
NSString *mainBundlePath = [[NSBundle mainBundle] bundlePath];
NSString *settingsPropertyListPath = [mainBundlePath
stringByAppendingPathComponent:#"Settings.bundle/Root.plist"];
NSDictionary *settingsPropertyList = [NSDictionary
dictionaryWithContentsOfFile:settingsPropertyListPath];
NSMutableArray *preferenceArray = [settingsPropertyList objectForKey:#"PreferenceSpecifiers"];
NSMutableDictionary *registerableDictionary = [NSMutableDictionary dictionary];
for (int i = 0; i < [preferenceArray count]; i++) {
NSString *key = [[preferenceArray objectAtIndex:i] objectForKey:#"Key"];
if (key) {
id value = [[preferenceArray objectAtIndex:i] objectForKey:#"DefaultValue"];
[registerableDictionary setObject:value forKey:key];
}
}
[[NSUserDefaults standardUserDefaults] registerDefaults:registerableDictionary];
[[NSUserDefaults standardUserDefaults] synchronize];
}
Make sure you are using - (void)registerDefaults:(NSDictionary *)dictionary on NSUserDefaults. Otherwise your defaults will not get pulled from the Bundle.
You have to do this early in your application, before you try to retrieve any of the default values.
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSUserDefaults_Class/Reference/Reference.html

Detecting the first ever run of an app

I am creating an app in which I have to create a plist when the app launches for the first time. I'm later going to use the plist to store details a user later inputs. How can I detect the first launch of the app? I was experimenting with NSUserDefaults but I think I'm doing something wrong.
You can do this with NSUserDefaults. But be careful with the Version Number.
Do the following:
NSString *bundleVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey];
NSString *appFirstStartOfVersionKey = [NSString stringWithFormat:#"first_start_%#", bundleVersion];
NSNumber *alreadyStartedOnVersion = [[NSUserDefaults standardUserDefaults] objectForKey:appFirstStartOfVersionKey];
if(!alreadyStartedOnVersion || [alreadyStartedOnVersion boolValue] == NO) {
[self firstStartCode];
[[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithBool:YES] forKey:appFirstStartOfVersionKey];
}
the selector firstStartCode will only be called on time for each application version on the very first run.
Okay?
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...
}
Taken from: Best way to check if an iPhone app is running for the first time
You can use the following:
-(void) firstLaunch {
//Code goes here
}
-(void) firstLaunchCheck {
if(![[NSUserDefaults standardUserDefaults] boolForKey:#"didLaunchFirstTime"]) {
[[NSUserDefaults standardUserDefaults] setBool:TRUE forKey:#"didLaunchFirstTime"];
[self firstLaunch];
}
}