How to save NSMutablearray in NSUserDefaults - ios

I have two NSMutableArray's. They consist of images or text.
The arrays are displayed via a UITableView.
When I kill the app the data within the UITableView gets lost.
How to save array in UITableView by using NSUserDefault?

Note: NSUserDefaults will always return an immutable version of the object you pass in.
To store the information:
// Get the standardUserDefaults object, store your UITableView data array against a key, synchronize the defaults
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject:arrayOfImage forKey:#"tableViewDataImage"];
[userDefaults setObject:arrayOfText forKey:#"tableViewDataText"];
[userDefaults synchronize];
To retrieve the information:
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSArray *arrayOfImages = [userDefaults objectForKey:#"tableViewDataImage"];
NSArray *arrayOfText = [userDefaults objectForKey:#"tableViewDataText"];
// Use 'yourArray' to repopulate your UITableView
On first load, check whether the result that comes back from NSUserDefaults is nil, if it is, you need to create your data, otherwise load the data from NSUserDefaults and your UITableView will maintain state.
Update
In Swift-3, the following approach can be used:
let userDefaults = UserDefaults.standard
userDefaults.set(arrayOfImage, forKey:"tableViewDataImage")
userDefaults.set(arrayOfText, forKey:"tableViewDataText")
userDefaults.synchronize()
var arrayOfImages = userDefaults.object(forKey: "tableViewDataImage")
var arrayOfText = userDefaults.object(forKey: "tableViewDataText")

You can save your mutable array like this:
[[NSUserDefaults standardUserDefaults] setObject:yourArray forKey:#"YourKey"];
[[NSUserDefaults standardUserDefaults] synchronize];
Later you get the mutable array back from user defaults. It is important that you get the mutable copy if you want to edit the array later.
NSMutableArray *yourArray = [[[NSUserDefaults standardUserDefaults] arrayForKey:#"YourKey"] mutableCopy];
Then you simply set the UITableview data from your mutable array via the UITableView delegate
Hope this helps!

I want just to add to the other answers that the object that you are going to store store in the NSUserDefault, as reported in the Apple documentation must be conform to this:
"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."
here the link to property list programming guide
so pay attention about what is inside your array

Save:
NSUserDefaults.standardUserDefaults().setObject(PickedArray, forKey: "myArray")
NSUserDefaults.standardUserDefaults().synchronize()
Retrieve:
if let PickedArray = NSUserDefaults.standardUserDefaults().stringForKey("myArray") {
print("SUCCCESS:")
println(PickedArray)
}

Do you really want to store images in property list? You can save images into files and store filename as value in NSDictionary.
define path for store files
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
self.basePath = [paths firstObject];
Store and load image:
- (NSString *)imageWithKey:(NSString)key {
NSString *fileName = [NSString stringWithFormat:#"%#.png", key]
return [self.basePath stringByAppendingPathComponent:fileName];
}
- (void)saveImage:(UIImage *)image withKey:(NSString)key {
NSData *imageData = UIImagePNGRepresentation(image);
[imageData writeToFile:[self imageWithKey:key] atomically:YES];
}
- (UIImage *)loadImageWithKey:(NSString)key { {
return [UIImage imageWithContentsOfFile:[self imageWithKey:key]];
}
And you can store path or indexes in NSMutableDictionary
- (void)saveDictionary:(NSDictionary *)dictionary {
NSMutableDictionary *dictForSave = [#{ } mutableCopy];
for (NSString *key in [dictionary allKeys]) {
[self saveImageWithKey:key];
dictForSave[key] = #{ #"image" : key };
}
[[NSUserDefaults standardUserDefaults] setObject:dictForSave forKey:#"MyDict"];
}
- (NSMutableDictionary *)loadDictionary:(NSDictionary *)dictionary {
NSDictionary *loadedDict = [[NSUserDefaults standardUserDefaults] objectForKey:#"MyDict"];
NSMutableDictionary *result = [#{ } mutableCopy];
for (NSString *key in [loadedDict allKeys]) {
result[key] = [self imageWithKey:key];
}
return result;
}
In NSUserDefaults you can store only simply objects like NSString, NSDictionary, NSNumber, NSArray.
Also you can serialize objects with NSKeyedArchiver/NSKeyedUnarchiver that conforms to NSCoding protocol .

If you need to add strings to the NSMutableArray in ant specific order, or if you are using the NSMutableArray for a UITableView you may want to use this instead:
[NSMutableArray insertObject:string atIndex:0];

In Swift 3, for an NSMutableArray, you will need to encode/decode your array to be able to save it/ retrieve it in NSUserDefaults :
Saving
//Encoding array
let encodedArray : NSData = NSKeyedArchiver.archivedData(withRootObject: myMutableArray) as NSData
//Saving
let defaults = UserDefaults.standard
defaults.setValue(encodedArray, forKey:"myKey")
defaults.synchronize()
Retrieving
//Getting user defaults
let defaults = UserDefaults.standard
//Checking if the data exists
if defaults.data(forKey: "myKey") != nil {
//Getting Encoded Array
let encodedArray = defaults.data(forKey: "myKey")
//Decoding the Array
let decodedArray = NSKeyedUnarchiver.unarchiveObject(with: encodedArray!) as! [String]
}
Removing
//Getting user defaults
let defaults = UserDefaults.standard
//Checking if the data exists
if defaults.data(forKey: "myKey") != nil {
//Removing the Data
defaults.removeObject(forKey: "myKey")
}

Save information of Array in NSUserdefaults with key.
"MutableArray received from JSON response"
[[NSUserDefaults standardUserDefaults] setObject:statuses forKey:#"arrayListing"];
"Retrieve this information(Array) anywhere in the project with same key"
NSArray *arrayList = [[NSUserDefaults standardUserDefaults] valueForKey:#"arrayListing"];
This helped me in my project and hope, it will help someone.

Swift Version:
Save Array in NSUserDefaults:
NSUserDefaults.standardUserDefaults().setObject(selection, forKey: "genderFiltersSelection")
Retrieve Bool Array From NSUserDefaults:
if NSUserDefaults.standardUserDefaults().objectForKey("genderFiltersSelection") != nil{
selection = NSUserDefaults.standardUserDefaults().objectForKey("genderFiltersSelection") as? [Bool] ?? [Bool]()
}
Retrieve String Array From NSUserDefaults:
if NSUserDefaults.standardUserDefaults().objectForKey("genderFiltersSelection") != nil{
selection = NSUserDefaults.standardUserDefaults().objectForKey("genderFiltersSelection") as? [String] ?? [String]()
}

Related

NSNumber numberWithBool changing the value of boolean from plist file

I have a plist file with the a key APICalls of type boolean set to NO.
I then retrieve this value in my code like this:
NSString *destinationPath= [doumentDirectoryPath stringByAppendingPathComponent:#"DefaultSettings.plist"];
NSMutableDictionary *defaultPreferences = [NSMutableDictionary dictionaryWithContentsOfFile:destinationPath];
NSLog(#"SETUP %#", defaultPreferences);
[[NSUserDefaults standardUserDefaults] registerDefaults:defaultPreferences];
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
NSMutableArray *tmp = [data objectForKey:#"user"];;
user.email = [tmp valueForKey:#"email"];
user.userId = [tmp valueForKey:#"id"];
user.username = [tmp valueForKey:#"username"];
user.APICall = [NSNumber numberWithBool:[defaults objectForKey:#"APICalls"]];
NSLog(#"API Call Value: %#", user.APICall);
My first log returns :
SETUP {
APICalls = 0;
TrackingTimer = 15;
VoiceMessages = 0;
}
Showing me the value of APICalls is 0.
But when I log user.APICall, I get
API Call Value: 1
Also user.APICall is of type NSNumber.
The problem is that objectForKey: of NSUserDefaults returns a cocoa object - in this case, it is probably an NSNumber. When you pass it to numberWithBool: method, it treats nil as NO, and everything else as YES.
If APICalls is set as a boolean, you can use it directly, like this:
user.APICall = [defaults objectForKey:#"APICalls"];
If APICalls is a number that you would like to re-interpret as a boolean, you can use this line instead:
user.APICall = [NSNumber numberWithBool:[[defaults objectForKey:#"APICalls"] intValue] != 0];
Don't forget to call [userDefaults synchronise].

Saving NSMutableDictionary containing UIButtons in the NSUserDefults

I am trying to save a NSMutableDictionary containing UIButtons in the NSUserDefults in this way:
[UserFolderDictionary setObject:FolderButton forKey:[NSString stringWithFormat:#"%ld", (long)numberFinal]];
[[NSUserDefaults standardUserDefaults] setObject:UserFolderDictionary forKey:#"UserFolderDictionarySaved"];
The app crashes with the error 'attempt to insert non-property list object'. To re-catch it I tried this:
NSMutableDictionary* UserFolderDictionary = [[[NSUserDefaults standardUserDefaults] dictionaryForKey:#"UserFolderDictionarySaved"] mutableCopy];
FolderButton is a normal UIButton with a tag and a background image.
You can't save buttons in NSUserDefaults, and furthermore you SHOULDN'T save buttons in NSUserDefaults.
Buttons are view objects, not model objects. You should save state information from your buttons, and then use that information to recreate your button.
You may try this.
`
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[myDictionary setObject:button forKey:#"myBtn"];
//save nsdata
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:myDictionary];
[userDefaults setObject:data forKey: #"SavedBtn"];
[userDefaults synchronize];
//now retrieve it
NSData *data1 = [userDefaults objectForKey:#"SavedBtn"];
NSDictionary *dict = [NSKeyedUnarchiver unarchiveObjectWithData:data1];
`
Hope that Helps!

NSUserDefaults Contains Value Or Not?

How to know whether NSUserDefaults contains any value?How to check whether its empty?
There isn't a way to check whether an object within NSUserDefaults is empty or not.
However, you can check whether a value for particular key is nil or not.
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
NSObject * object = [prefs objectForKey:#"your_particular_key"];
if(object != nil){
//object is there
}
NSUserDefaults *data = [NSUserDefaults standardUserDefaults];
NSString *string = [data objectForKey:#"yourKey"];
if(string==nil)
NSlog(#"nil")
Take a look at NSUserDefault documentation
// For saving the values
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
// saving an NSString
[userDefaults setObject:#"Ttest" forKey:#"key"];
// --- For Retrieving
NSUserDefaults * userDefaults = [NSUserDefaults standardUserDefaults];
// getting an NSString
NSString *myString = [userDefaults stringForKey:#"key"];
To check whether a specific value is set or not, no matter of its location (global or application's), check the returned value of -[NSUserDefaults objectForKey:]
id obj = [[NSUserDefaults standardUserDefaults] objectForKey:#"My-Key-Name"];
if (obj != nil) {...}
To check if the application (bundle) has any settings stored in user defaults:
NSUserDefaults* sdu = [NSUserDefaults standardUserDefaults];
NSString* bundleId = [[NSBundle mainBundle] bundleIdentifier];
NSDictionary* mainBundleSettings = [sdu persistentDomainForName:bundleId];
NSLog(#"%#", mainBundleSettings);
If you are interested in all possible values for which -[NSUserDefaults objectForKey:] will return something, including system global settings, simply call
NSDictionary* allPossibleSettings = [sdu dictionaryRepresentation];
NSUserDefaults is never empty. It combines global settings, bundle's settings, temporary data and maybe something else. For example, if you call:
[[NSUserDefaults standardUserDefaults] objectForKey:#"NSBoldSystemFont"]
you will get the #"LucidaGrande-Bold" string value which will be taken from global settings, even when your application has never set this value.

Delete all keys from a NSUserDefaults dictionary iOS

I use the NSUserDefaults dictionary to store basic information such as high scores etc so that when the user closes the app data is not lost. Anyways I use:
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
to store data. If I wish to store a new high score for example then I would do:
[prefs setInteger:1023 forKey:#"highScore"];
[prefs synchronize]; //this is needed in case the app is closed.
and later if I wish to retrieve the high score I would do:
[prefs integerForKey:#"highScore"];
anyways the point is that I store a lot of other things because the NSUserDefaults enable you to store booleans, integers, objects etc. what method would I have to execute to delete all keys so that NSUserDefaults becomes like the fist time I launch the app?
I am looking for something like:
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
[prefs deleteAllKeysAndObjectsInTheDictionary];
or maybe there is a way of getting all keys and I have to loop through each object but I don't know how to remove them.
EDIT:
I have tried :
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
[NSUserDefaults resetStandardUserDefaults];
[prefs synchronize];
and I still am able to retrieve a high score....
If you have a look at the NSUserDefaults documentation you will see a method - (NSDictionary *) dictionaryRepresentation. Using this method on the standard user defaults, you can get a list of all keys in the user defaults. You can then use this to clear the user defaults:
- (void)resetDefaults {
NSUserDefaults * defs = [NSUserDefaults standardUserDefaults];
NSDictionary * dict = [defs dictionaryRepresentation];
for (id key in dict) {
[defs removeObjectForKey:key];
}
[defs synchronize];
}
Shortest way to do this with the same results like in Alex Nichol's top answer:
NSString *appDomain = NSBundle.mainBundle.bundleIdentifier;
[[NSUserDefaults standardUserDefaults] removePersistentDomainForName:appDomain];
[[NSUserDefaults standardUserDefaults] synchronize];
One-liner:
[[NSUserDefaults standardUserDefaults] removePersistentDomainForName:NSBundle.mainBundle.bundleIdentifier];
Simple Solution
Objective C:
NSString *appDomain = [[NSBundle mainBundle] bundleIdentifier];
[[NSUserDefaults standardUserDefaults] removePersistentDomainForName:appDomain];
Swift 3.0 to Swift 5.0 :
if let appDomain = Bundle.main.bundleIdentifier {
UserDefaults.standard.removePersistentDomain(forName: appDomain)
}
Swift version:
if let bid = NSBundle.mainBundle().bundleIdentifier {
NSUserDefaults.standardUserDefaults().removePersistentDomainForName(bid)
}
+ (void) resetStandardUserDefaults doesn't persist the changes, it simply resets the in-memory user defaults object so that the next synchronize call will read from the on-disk copy, instead of overwriting existing in-memory values with the on-disk versions.
Iterating over the keys is better, but there's actually a function that does this for you: removePersistentDomainForName:.
// you can usually get the domain via [[NSBundle mainBundle] bundleIdentifier]
[[NSUserDefaults standardUserDefaults]
removePersistentDomainForName:[[NSBundle mainBundle] bundleIdentifier]];
// or use a string for any other settings domains you use
//[[NSUserDefaults standardUserDefaults]
// removePersistentDomainForName:#"com.mycompany.myappname"];
[[NSUserDefaults standardUserDefaults] synchronize];
At the end of the synchronize operation, both the disk and memory copies of user defaults will contain none of the values set by your application.
Oneliner in Swift:
Swift 3
NSUserDefaults.standardUserDefaults().removePersistentDomainForName(
NSBundle.mainBundle().bundleIdentifier!)
Swift 4
UserDefaults.standard.removePersistentDomain(forName: Bundle.main.bundleIdentifier!)
For those of you that want to do this in the test target, use this (as the removePersistentDomain does not work for that case)
Swift 3:
for key in Array(UserDefaults.standard.dictionaryRepresentation().keys) {
UserDefaults.standard.removeObject(forKey: key)
}
For Swift 3:
let appDomain = Bundle.main.bundleIdentifier!
UserDefaults.standard.removePersistentDomain(forName: appDomain)
For Swift 3:
if let bundle = Bundle.main.bundleIdentifier {
UserDefaults.standard.removePersistentDomain(forName: bundle)
}
I found it the most handy to place the code in an extension on UserDefaults.
Swift 5
extension UserDefaults {
static func clear() {
guard let domain = Bundle.main.bundleIdentifier else { return }
UserDefaults.standard.removePersistentDomain(forName: domain)
UserDefaults.standard.synchronize()
}
}
Usage
UserDefaults.clear()
Swift
place in your logic
if let appDomain = Bundle.main.bundleIdentifier {
UserDefaults.standard.removePersistentDomain(forName: appDomain)
}
Swift
func resetUserDefaults(){
let userDefaults = NSUserDefaults.standardUserDefaults()
let dict = userDefaults.dictionaryRepresentation() as NSDictionary
for key in dict.allKeys {
userDefaults.removeObjectForKey(key as! String)
}
userDefaults.synchronize()
}
Does this method not do that:
+ (void)resetStandardUserDefaults
From the documentation for NSUserDefaults:
resetStandardUserDefaults
Synchronizes any changes made to the shared user defaults object and
releases it from memory.
+ (void)resetStandardUserDefaults
Discussion
A subsequent invocation of standardUserDefaults creates a new shared
user defaults object with the standard search list.
Based on this, you can do:
[NSUserDefaults resetStandardUserDefaults];
[NSUserDefaults standardUserDefaults];
and now the defaults should be reset.
Swift 3 or 4
We can even simplify described snippet into this modern expression:
func clearAll() {
let settingsDictionary = userDefaults.dictionaryRepresentation()
settingsDictionary.forEach { key, _ in userDefaults.removeObject(forKey: key) }
userDefaults.synchronize()
}
To remove all UserDefault value in swift (Latest syntax)
//remove UserDefaults
if let identifier = Bundle.main.bundleIdentifier {
UserDefaults.standard.removePersistentDomain(forName: identifier)
UserDefaults.standard.synchronize()
}
In Swift 5.0 below single line of code is enough.
UserDefaults.standard.dictionaryRepresentation().keys.forEach(defaults.removeObject(forKey:))
I use this:
UserDefaults.standard.removeAll()

How do I save user preferences for my iPhone app?

The question title pretty much gives it away - I'd like my app to remember a few things. It's some sort of calculator, so it should save the last used values and some user selectable settings.
Basically I'd like to save a handful of floats and BOOLs and load them again the next time the app loads.
What's the best and easiest way to do that?
Thanks!!
One of the easiest ways would be saving it in the NSUserDefaults:
Setting:
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject:value
forKey:key];
// – setBool:forKey:
// – setFloat:forKey:
// in your case
[userDefaults synchronize];
Getting:
[[NSUserDefaults standardUserDefaults] objectForKey:key];
– boolForKey:
and
– floatForKey: in your case.
Besides the very good NSUserDefaults approach, there is another easy way to store data from an NSArray,NSDictionary or NSData in a file. You can use these methods as well:
- (BOOL)writeToFile:(NSString *)path atomically:(BOOL)flag
respectively (for a NSDictionary):
+ (id)dictionaryWithContentsOfFile:(NSString *)path
you just have to give a valid path to a location. According to the iOS Application Programming Guide, the /Library/Caches directory would be the best place to store data that you need to persist between app launches. (see here)
In order to store/load a dictionary from a filed called "managers" in your document directoy you could use these methods:
-(void) loadDictionary {
//get the documents directory:
NSArray *paths = NSSearchPathForDirectoriesInDomains (NSCachesDirectory, NSUserDomainMask, YES);
NSString *cacheDirectory = [paths objectAtIndex:0];
//create a destination file name to write the data :
NSString *fullFileName = [NSString stringWithFormat:#"%#/managers", cacheDirectory];
NSDictionary* panelLibraryContent = [NSDictionary dictionaryWithContentsOfFile:fullFileName];
if (panelLibraryContent != nil) {
// load was successful do something with the data...
} else {
// error while loading the file
}
}
-(void) storeDictionary:(NSDictionary*) dictionaryToStore {
//get the documents directory:
NSArray *paths = NSSearchPathForDirectoriesInDomains
(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cacheDirectory = [paths objectAtIndex:0];
//make a file name to write the data to using the
//cache directory:
NSString *fullFileName = [NSString stringWithFormat:#"%#/managers", cacheDirectory];
if (dictionaryToStore != nil) {
[dictionaryToStore writeToFile:fullFileName atomically:YES];
}
}
Anyway this approach is very limited and you have to spend a lot of extra work if you want to store more complex data. In that case the CoreData API is very very handy.
In Swift:
Setting
let userDefaults = NSUserDefaults.standardUserDefaults()
userDefaults.setObject(value, forKey: key)
// userDefaults.setFloat(12.34, forKey: "myFloatKey")
// userDefaults.setBool(true, forKey: "myBoolKey")
Note that for iOS 8 and later, calling userDefaults.synchronize() is not recommended.
Getting
let userDefaults = NSUserDefaults.standardUserDefaults()
if let value = userDefaults.objectForKey(key) {
print(value)
}
Note that userDefaults.boolForKey and userDefaults.floatForKey both return non optional values, so they would never be nil (only false or 0.0).
Further reading
NSUserDefaults — A Swift Introduction
You are looking for NSUserDefaults
Swift 4 / Linux
Apparently something has changed. Now there's the UserDefault class.
Check these links:
https://developer.apple.com/documentation/foundation/userdefaults
https://www.hackingwithswift.com/read/12/2/reading-and-writing-basics-userdefaults

Resources