NSUserDefaults removeObjectForKey vs. setObject:nil - nsuserdefaults

Are the following two lines equivalent?
1.
[[NSUserDefaults standardUserDefaults] removeObjectForKey:#"example key"]
2.
[[NSUserDefaults standardUserDefaults] setObject:nil forKey:#"example key"]

Yes, both lines of code are equivalent, both will result in nil read
id obj = [[NSUserDefaults standardUserDefaults] objectForKey:#"example key"];
NSUserDefaults will return nil if the key was not found. I would recommend to use the removeObjectForKey instead of setting it to nil.
here is how to test if setting key value to nil removed the key entry from NSUserDefaults standardUserDefaults.
NSArray *keys = [[[NSUserDefaults standardUserDefaults] dictionaryRepresentation] allKeys] copy];
for(NSString *key in keys) {
NSLog(#"Key Name: %#", key);
}
[keys release];
or simply dump the key/value dictionary of NSUserDefaults standardUserDefaults
NSLog(#"All contents of NSUserDefaults: %#", [[NSUserDefaults standardUserDefaults] dictionaryRepresentation]);

Swift 3.0
The below answer is no longer the case when I tested this.
When set to nil the result is NSCFData being stored. Possibly an NSNull object reference, but I am not positive.
To completely remove a value for a key use UserDefaults.standard.removeObject(forKey: "YourDefault")
I tested with the following code:
UserDefaults.standard.set(["a", "b", "c"], forKey: "MyDefaults")
print("Test A: My saved defaults \(UserDefaults.standard.object(forKey: "MyDefaults"))")
UserDefaults.standard.set(nil, forKey: "MyDefaults")
print("Test B: My defaults set to nil \(UserDefaults.standard.object(forKey: "MyDefaults"))")
UserDefaults.standard.removeObject(forKey: "MyDefaults")
print("Test C: My defaults removed \(UserDefaults.standard.object(forKey: "MyDefaults"))")

Swift 5.0 + iOS 11 and up
Both methods remove the value. Tried this in a playground:
import Foundation
let key = "Test"
let value = "test"
let defaults = UserDefaults.standard
func printUD() {
print("UserDefaults after modification:\n")
defaults.dictionaryRepresentation().forEach { print("\($0): \($1)\n") }
print("-------------\n\n")
}
defaults.set(value, forKey: key); printUD()
defaults.set(nil, forKey: key); printUD()
defaults.set(value, forKey: key); printUD()
defaults.removeObject(forKey: key); printUD()
Prior to iOS 11 this will result in serializing nil into Data and throw an error.

Related

Is there a way to get all values in NSUserDefaults? [duplicate]

This question already has answers here:
Easy way to see saved NSUserDefaults?
(24 answers)
Closed 9 years ago.
I would like to print all values I saved via NSUserDefaults without supplying a specific Key.
Something like printing all values in an array using for loop. Is there a way to do so?
Objective C
all values:
NSLog(#"%#", [[[NSUserDefaults standardUserDefaults] dictionaryRepresentation] allValues]);
all keys:
NSLog(#"%#", [[[NSUserDefaults standardUserDefaults] dictionaryRepresentation] allKeys]);
all keys and values:
NSLog(#"%#", [[NSUserDefaults standardUserDefaults] dictionaryRepresentation]);
using for:
NSArray *keys = [[[NSUserDefaults standardUserDefaults] dictionaryRepresentation] allKeys];
for(NSString* key in keys){
// your code here
NSLog(#"value: %# forKey: %#",[[NSUserDefaults standardUserDefaults] valueForKey:key],key);
}
Swift
all values:
print(UserDefaults.standard.dictionaryRepresentation().values)
all keys:
print(UserDefaults.standard.dictionaryRepresentation().keys)
all keys and values:
print(UserDefaults.standard.dictionaryRepresentation())
You can use:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSDictionary *defaultAsDic = [defaults dictionaryRepresentation];
NSArray *keyArr = [defaultAsDic allKeys];
for (NSString *key in keyArr)
{
NSLog(#"key [%#] => Value [%#]",key,[defaultAsDic valueForKey:key]);
}
Print only keys
NSLog(#"%#", [[[NSUserDefaults standardUserDefaults] dictionaryRepresentation] allKeys]);
Keys and Values
NSLog(#"%#", [[NSUserDefaults standardUserDefaults] dictionaryRepresentation]);
You can log all of the contents available to your app using:
NSLog(#"%#", [[NSUserDefaults standardUserDefaults] dictionaryRepresentation]);

find special keys in UserDefaults by "substringToIndex"

I'm grouping my UserDefault keys by specific prefixes.
e.g.
[NSUserDefaults standardUserDefaults] setInteger: 1 forKey: #"prefix1_someText_Key"]
[NSUserDefaults standardUserDefaults] setInteger: 2 forKey: #"prefix2_someText_Key"]
[NSUserDefaults standardUserDefaults] setInteger: 3 forKey: #"prefix4_someText_Key"]
//.....
Now, I'd like to find all the keys, that start with e.g. "prefix", and load them into an array. is there a way for doing that (programmatically)?
You could use the underlying NSDictionary to find the suitable keys:
NSString *myPrefix = #"prefix";
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSDictionary *dict = [defaults dictionaryRepresentation];
NSMutableArray *keysWithPrefix = [NSMutableArray array]
for (NSString *key in dict.keyEnumerator) {
if ([key hasPrefix: myPrefix]) {
[keysWithPrefix addObject: key];
}
}
// now keysWithPrefix contains all matching keys
UPDATE
For debugging reasons you could add a log to see what keys are being dropped:
for (NSString *key in dict.keyEnumerator) {
if ([key hasPrefix: myPrefix]) {
[keysWithPrefix addObject: key];
} else {
NSLog(#"Dropping key %#", key);
}
}

How to store a float in NSUserDefaults

I want to store a float value into NSUserDefaults.
I also need to check that the float value exists..if not I need to assign some value in it.
and retrieve it...for the above I have the below code but it gives me an error.
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if ([defaults boolForKey:#"HANDWRITING_SIZE_SLIDER"] == YES) {
self.sizeSlider.value = 10.0;
} else {
self.sizeSlider.value = [[NSUserDefaults standardUserDefaults] floatForKey:#"HANDWRITING_SIZE_SLIDER"]];
}
Thanks for any help
Use the NSNumber class for this and store it via the setObject:forKey: method so you can check if it exists.
I'd also suggest the usage of constants as keys:
#define HANDWRITING_SIZE_SLIDER #"HSS"
Your code should be along these lines:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if ([defaults objectForKey:HANDWRITING_SIZE_SLIDER] == nil) {
//doesn't exist in NSUserDefaults, set to default value...
self.sizeSlider.value = 10.0;
} else {
self.sizeSlider.value = [[defaults objectForKey:HANDWRITING_SIZE_SLIDER] floatValue];
}
Somewhere else in your app, you'd set the value in NSUserDefaults like this:
float sizeSliderValue = ...
[[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithFloat:sizeSliderValue] forKey:HANDWRITING_SIZE_SLIDER];
Try this code:
-(IBAction)sliderAction:(id)sender
{
float sliderValue = [sender floatValue];
[[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithFloat:sliderValue] forKey:#"keySliderValue"];
NSLog(#"%#",[[NSUserDefaults standardUserDefaults] objectForKey:#"keySliderValue"]);
}

IPhone SDK Default NSUserDefaults

I have set up the user defaults to record a integer for a UISlider, the problem is that, if the user has only just installed the app then the integer is zero or NULL. Is there a way to detect if it = NULL with a integer?
heres my code i have so far:
-(void)awakeFromNib {
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
senset = [prefs integerForKey:#"senset"];
senset = sensitivity.value;
}
- (IBAction) setSens {
senset = sensitivity.value;
}
- (IBAction) goBackopt {
{
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
[prefs setInteger:senset forKey:#"senset"];
[prefs synchronize];
}
}
senset is the integer. i have tried this code, and it sets it to 25 on the first time, but then if i try and overwrite it, it wont work and keeps setting it to 25. :(
if ( [prefs integerForKey:#"senset"] == NULL ) {
senset = 25;
}
Please help :P
Harry
You should set a valid default value for each of your preferences. This value will be used when one has not been set by the user.
NSMutableDictionary *defaults = [NSMutableDictionary dictionary];
[defaults setObject:[NSNumber numberWithInt:25] forKey:#"senset"];
[[NSUserDefaults standardUserDefaults] registerDefaults:defaults];
Just ask for objectForKey:. If it isn't set, it will return nil.
Your test doesn't work, because integerForKey: with an unset value will return 0, which is nil, which is NULL. The differences between them only exist to the compiler.
If zero is not a valid value in a normal usage case (i.e. your saved preference would never set this integer to zero), then you can check
if( [prefs integerForKey:#"senset"] == 0){
[prefs setInteger:25 forKey:#"senset"];
}
Edit: err, I suppose I have a question: when you try to overwrite it, are you setting an integer value(25) for your key (#"senset")? If not, then it will remain zero or nil, and everytime you check it will attempt to change your local senset variable to 25 again.

iPhone App : How to get default value from root.plist?

I am working on an iPhone app
I read a key from root.plist like this :
NSString *Key1Var = [[NSUserDefaults standardUserDefaults] stringForKey:#"Key1"];
("Key1" is a PSMultiValueSpecifier for which a default string value has been set already in root.plist)
That works fine, once the user makes settings.
But if the user runs the app before he does any setting, he will get nil for "Key1".
In such case, I was expecting the default value that i had set for "Key1".
what i need to do,
so that the user does not have to do setting, to make application run for the first time?
Regards,
Harish
See this question for a complete solution.
You essentially want to run this code before accessing the setting:
- (void)registerDefaultsFromSettingsBundle {
NSString *settingsBundle = [[NSBundle mainBundle] pathForResource:#"Settings" ofType:#"bundle"];
if(!settingsBundle) {
NSLog(#"Could not find Settings.bundle");
return;
}
NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[settingsBundle stringByAppendingPathComponent:#"Root.plist"]];
NSArray *preferences = [settings objectForKey:#"PreferenceSpecifiers"];
NSMutableDictionary *defaultsToRegister = [[NSMutableDictionary alloc] initWithCapacity:[preferences count]];
for(NSDictionary *prefSpecification in preferences) {
NSString *key = [prefSpecification objectForKey:#"Key"];
if(key) {
[defaultsToRegister setObject:[prefSpecification objectForKey:#"DefaultValue"] forKey:key];
}
}
[[NSUserDefaults standardUserDefaults] registerDefaults:defaultsToRegister];
[defaultsToRegister release];
}
This will load the default values into the standardUserDefaults object so you will no longer get back nil values, and you don't have to duplicate the default settings in your code.
I do this early after launch, before I try to get my settings:
userDefaultsValuesPath=[[NSBundle mainBundle] pathForResource:#"UserDefaults"
ofType:#"plist"];
userDefaultsValuesDict=[NSDictionary dictionaryWithContentsOfFile:userDefaultsValuesPath];
// set them in the standard user defaults
[[NSUserDefaults standardUserDefaults] registerDefaults:userDefaultsValuesDict];
if (![[NSUserDefaults standardUserDefaults] synchronize])
NSLog(#"not successful in writing the default prefs");
A Swift 3 version based on Mike Weller's original solution if anyone needs it:
static func registerDefaultsFromSettingsBundle() {
guard let settingsBundle = Bundle.main.url(forResource: "Settings", withExtension: "bundle") else {
print("Could not find Settings.bundle")
return
}
guard let settings = NSDictionary(contentsOf: settingsBundle.appendingPathComponent("Root.plist")) else {
print("Couldn't find Root.plist in settings bundle")
return
}
guard let preferences = settings.object(forKey: "PreferenceSpecifiers") as? [[String: AnyObject]] else {
print("Root.plist has an invalid format")
return
}
var defaultsToRegister = [String: AnyObject]()
for var p in preferences {
if let k = p["Key"] as? String, let v = p["DefaultValue"] {
print("Registering " + v.debugDescription + " for key " + k)
defaultsToRegister[k] = v as AnyObject
}
}
UserDefaults.standard.register(defaults: defaultsToRegister)
}
Here is the code I use in iOS 7, based heavily on Mike Weller's code above.
Put this method in your AppDelegate.m:
- (void)registerDefaultsFromSettingsBundleWithPlist:(NSString *)plist {
NSString *settingsBundle = [[NSBundle mainBundle] pathForResource:#"Settings" ofType:#"bundle"];
if(!settingsBundle) {
NSLog(#"Could not find Settings.bundle");
return;
}
NSString *bundle = [NSString stringWithFormat:#"%#.plist",plist];
NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[settingsBundle stringByAppendingPathComponent:bundle]];
NSArray *preferences = [settings objectForKey:#"PreferenceSpecifiers"];
NSMutableDictionary *defaultsToRegister = [[NSMutableDictionary alloc] initWithCapacity:[preferences count]];
for(NSDictionary *prefSpecification in preferences) {
NSString *key = [prefSpecification objectForKey:#"Key"];
if(key) {
[defaultsToRegister setObject:[prefSpecification objectForKey:#"DefaultValue"] forKey:key];
}
}
[[NSUserDefaults standardUserDefaults] registerDefaults:defaultsToRegister];
//[defaultsToRegister release];
}
And then call it for every settings file you're using (for nested settings), from some place early in your code like didFinishLaunchingWithOptions:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//register default settings into NSUserDefaults
#try {
[self registerDefaultsFromSettingsBundleWithPlist:#"Root"];
[self registerDefaultsFromSettingsBundleWithPlist:#"Chat"];
[self registerDefaultsFromSettingsBundleWithPlist:#"IVR"];
[self registerDefaultsFromSettingsBundleWithPlist:#"Video"];
}
#catch (NSException * e) {
NSLog(#"Exception: %#", e);
NSLog(#"Try adding the Default Value field to each preference item in the Settings.bundle plist files.");
}
#finally {
}
...
I've translated Mike Weller's solution into Swift 2.0/iOS 9 and made it work for my App:
func registerDefaultsFromSettingsBundle() {
guard let settingsBundle = NSBundle.mainBundle().URLForResource("Settings", withExtension:"bundle") else {
NSLog("Could not find Settings.bundle")
return;
}
guard let settings = NSDictionary(contentsOfURL: settingsBundle.URLByAppendingPathComponent("Root.plist")) else {
NSLog("Could not find Root.plist in settings bundle")
return
}
guard let preferences = settings.objectForKey("PreferenceSpecifiers") as? [[String: AnyObject]] else {
NSLog("Root.plist has invalid format")
return
}
var defaultsToRegister = [String: AnyObject]()
for var p in preferences {
if let k = p["Key"] as? String, v = p["DefaultValue"] {
NSLog("%#", "registering \(v) for key \(k)")
defaultsToRegister[k] = v
}
}
NSUserDefaults.standardUserDefaults().registerDefaults(defaultsToRegister)
}
In my application delegate, I override the +initialize method and register new application default preferences.
For example:
+ (void) initialize {
if ([self class] == [MyAppDelegate class]) {
// initialize user defaults dictionary
BOOL isFirstTimeRun = YES;
BOOL isKeychainTurnedOn = NO;
BOOL isSSLTurnedOn = YES;
NSString *testURLString = #"http://stackoverflow.com";
NSMutableDictionary *resourceDict = [NSMutableDictionary dictionary];
[resourceDict setObject:[NSNumber numberWithBool:isFirstTimeRun] forKey:kIsFirstTimeRunKey];
[resourceDict setObject:[NSNumber numberWithBool:isKeychainTurnedOn] forKey:kIsKeychainTurnedOnKey];
[resourceDict setObject:[NSNumber numberWithBool:isSSLTurnedOn] forKey:kIsSSLTurnedOnKey];
[resourceDict setObject:testURLString forKey:kTestURLString];
[[NSUserDefaults standardUserDefaults] registerDefaults:resourceDict];
}
}
NSBundle* mainBundle = [NSBundle mainBundle]; 
 
// Reads the value of the custom key I added to the Info.plist
NSString *value = [mainBundle objectForInfoDictionaryKey:#"key"];
//Log the value
NSLog(#"Value = %#", value);
// Get the value for the "Bundle version" from the Info.plist
[mainBundle objectForInfoDictionaryKey:#"CFBundleVersion"];
// Get the bundle identifier
[mainBundle bundleIdentifier];