How do I save user preferences for my iPhone app? - ios

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

Related

Where to store Dictionary data in iOS

I am developing iPhone app,i have one doubt
I have an NSMutableDictionary which contains data in this format
dict at 0th index:
"ProductId":"77386",
"ProductImage":"http://static.abcd.com/images/product/large/design_gallery_slide_green - Copy (2).jpg",
"Productshortname":"Apple iPhone 5c 16GB",
"categorycode":null,
"categoryid":8,
"categoryimage":"",
"categoryshortname":"",
"favorite":"0",
"price":"31500",
"productnameinUrl":"apple-iphone-5c-16gb",
"storecount":"10"
dict at 1st index:
"ProductId":"11386",
"ProductImage":"http://static.abcd.com/images/product/large/design_gallery_slide_green - Copy (2).jpg",
"Productshortname":"Apple iPhone 5s 16GB",
"categorycode":null,
"categoryid":8,
"categoryimage":"",
"categoryshortname":"",
"favorite":"1",
"price":"31500",
"productnameinUrl":"apple-iphone-5s-16gb",
"storecount":"18"
dict at 2nd index:
"ProductId":"31386",
"ProductImage":"http://static.abcd.com/images/product/large/design_gallery_slide_green - Copy (2).jpg",
"Productshortname":"Apple iPhone 4s 16GB",
"categorycode":null,
"categoryid":8,
"categoryimage":"",
"categoryshortname":"",
"favorite":"1",
"price":"31500",
"productnameinUrl":"apple-iphone-4s-16gb",
"storecount":"38"
and so on...
What i want to do is, i want to store this dictionary indexes some where in my directory and i want to fetch it after some time or even after closing and opening the app after few times.
where should i store this kind of data ? is there any storage for strong this kind of data?
Please help and thanks in advance !!
You can store the data in NSUserdefaults and can access any time and anywhere as you want
yourdict;//Your NSDictionary Object That contains the data to store
[[NSUserDefaults standardUserDefaults] setObject:yourdict forKey:#"dict"];
[[NSUserDefaults standardUserDefaults] synchronize];
At the time of retrieval of data,
dict = [[NSUserDefaults standardUserDefaults] objectForKey:#"dict"];
You've already chosen an approved answer but I'll throw my thoughts in anyway.
This information looks like it could get large.
The user defaults isn't designed for large chunks of data. It's really meant for small bits of information, such as boolean preferences etc etc, not to be treated as an easy-to-use database.
Some problems with the user defaults:
The defaults file is read and parsed when you launch your app, regardless of whether you need your information from it at that time or not. This is because other parts of your app also use it for storing their bits of info too.
The entire defaults file needs to be parsed in order for you to retrieve anything, even if you just want a single entry.
You don't choose when the defaults file is parsed. You can't do any smart threading if it becomes huge (say you put 1000 products in there)
I'd recommend either writing the dictionary to it's own plist using NSDictionary's writeToFile: and reading using initWithContentsOfFile: (this still suffers from point #2 above)
OR
Using CoreData/sqlite to write the information to a real database.
NSDictionary methods: https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSDictionary_Class/Reference/Reference.html#//apple_ref/occ/instm/NSDictionary/writeToFile:atomically:
An other option (And better in my experience) is to use - NSCoder, this option is great as you can use an Object with normal properties to access your data, which make your code more readable.
You can read about it here - NSCoding / NSKeyed​Archiver by NSHipster
An here is the reference - NSCoder docs
NSDictionary has a writeToFile: method which will do it for you.
NSDicationary writeToFile:Atomically:
use NSUserDefault and save your data like this in array
Here you can use this in anyway in your application for store value of NSUserDefaults.
// --- Saving
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
// saving an NSString
[prefs setObject:#"TextToSave" forKey:#"keyToLookupString"];
// saving an NSInteger
[prefs setInteger:42 forKey:#"integerKey"];
// saving a Double
[prefs setDouble:3.1415 forKey:#"doubleKey"];
// saving a Float
[prefs setFloat:1.2345678 forKey:#"floatKey"];
// This is suggested to synch prefs, but is not needed (I didn't put it in my tut)
[prefs synchronize];
Here you can use this in anyway in your application for get value of NSUserDefaults.
// --- Retrieving
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
// getting an NSString
NSString *myString = [prefs stringForKey:#"keyToLookupString"];
// getting an NSInteger
NSInteger myInt = [prefs integerForKey:#"integerKey"];
// getting an Float
float myFloat = [prefs floatForKey:#"floatKey"];
Thanks & Cheers ..
Looks like there can be more amount of data, so the best approach is to use core data to handle this scenario.
You can check few tutorials on how to use core data - Link1 , Link2
There are advantage of using core data over NSUserDefault and file system, as those load all the data at once and you might face some issue in performance.
You can also check following links which will illustrate you performance of different mechanism used to store data - PerformanceLinks1 PerformanceLinks2
try this
NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:
#"audio.caf",#"pictureAudioKey",
#"audio.m4a",#"englishAudioKey",
#"audio2.m4a",#"spanishAudioKey",
#"audio3.m4a",#"frenchAudioKey",
#"audio4.m4a",#"germanAudioKey",
#"audio5.m4a",#"italianAudioKey",
#"audio6.m4a",#"chineseAudioKey",
#"image.jpg",#"photoimagekey",
#"name.txt", #"identity",
#"imagename.txt",#"numberkey",nil];
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [documentPaths objectAtIndex:0];
NSString *dictionaryPath = [documentsDirectory stringByAppendingPathComponent:[[self imageNameTextField]text]];
dictionaryPath =[dictionaryPath stringByAppendingFormat:#"dicitonary" ] ;
NSDictionary *savedDictionary = dictionary;
NSLog(#"The Save file is:%#", savedDictionary);
[savedDictionary writeToFile:dictionaryPath atomically:YES];

local memory as well as webservice

even after so many research i haven't found a solution for this question. I am currently working on a app which uses 3 view controllers for Registration with a log out button. the last view controller has the Register button which saves all the details of registration in a web service. But if the user has filled the two view forms and logs out. The two view filled forms field should be saved in the local memory and wen the user logs it again the pre filled forms should load the fields saved in internal memory just to continue the Registration for webservice. Any idea how to implement this sort of functionality
As others have said, NSUserDefaults will suffice for what you need.
NSUserDefaults *registrationInfo = [NSUserDefaults standardUserDefaults];
Guessing you have text fields with the info you need. So pull out the text and save to a key like this.
[registrationInfo setObject:self.someTextFieldName.text forKey#"firstTextField"];
After repeating this for every text field(use different key names though), call this [registrationInfo synchronize];
To pull the data out, you open the defaults again just like the first line. And to retrieve a specific key: NSString *firstTextField = [registrationInfo objectForKey:#"firstTextField"];
To make this easier, you can also put all of your strings in an array or dictionary, and then add that as an object in your defaults. Then you only have to set/get once.
If you have large amount of data to save use CoreData else you NSUserDefaults to save it.
I suggest you to use PLIST There are mainly three steps to do this.
1) Generate .plist file.
NSError *error1;
BOOL resourcesAlreadyInDocumentsDirectory;
BOOL copied1;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath1 = [documentsDirectory stringByAppendingString:#"/epub.plist"];
resourcesAlreadyInDocumentsDirectory = [fileManager fileExistsAtPath:filePath1];
if(resourcesAlreadyInDocumentsDirectory == YES) {
} else {
NSString *path1 = [[[NSBundle mainBundle] resourcePath] stringByAppendingFormat:#"/epub.plist"];
copied1 = [fileManager copyItemAtPath:path1 toPath:filePath1 error:&error1];
if (!copied1) {
NSAssert1(0, #"Failed to copy epub.plist. Error %#", [error1 localizedDescription]);
}
}
2) Try to read(open) it.
NSMutableDictionary* dict = [[NSMutableDictionary alloc] initWithContentsOfFile:filePath1];
3) write data to plist file.
[dict setObject:[NSNumber numberWithInt:value] forKey:#"value"];
[dict writeToFile:path atomically:YES];
This is a simple way to use it. I suggest to use .plist file in place of NSUserDefaults.

Saving Successfully, but not Visibly Editing plist

So this is my first time trying to save data in an iOS app. I've pieced together this code from various answers on this site in order to save a high score for a game I'm making. I created a plist named saves.plist (in my Supporting Files folder) and added a row of key #"bestScore" and type Number. The test log returns that the save is successful, and everything works; however, when I go to look at the plist after, nothing seems to have changed (the value of bestScore is 0). Am I saving to a different plist that is automatically created in my code? If this is the case, what is the point of being able to create plists in Xcode, and what is the best practice to use here as far as where/how to create/store/access plists?
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.fm = [NSFileManager defaultManager];
self.destPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];//Documents directory
self.destPath = [self.destPath stringByAppendingPathComponent:#"saves.plist"];
// If the file doesn't exist in the Documents Folder, copy it.
if (![self.fm fileExistsAtPath:self.destPath]) {
NSString *sourcePath = [[NSBundle mainBundle] pathForResource:#"saves" ofType:#"plist"];
[self.fm copyItemAtPath:sourcePath toPath:self.destPath error:nil];
}
}
- (void)saveBestScore{
NSNumber *bestScoreBox = [NSNumber numberWithUnsignedLong:self.bestScore];
NSDictionary *data = #{bestScoreBox: #"bestScore"};
BOOL successful = [data writeToFile:self.destPath atomically:YES];
successful ? NSLog(#"YES") : NSLog(#"NO");
}
When you say
when I go to look at the plist after, nothing seems to have changed
(the value of bestScore is 0)
Do you mean looking at the plist in xcode project files ? You have copied the plist into a device directory and therefore you wont be able to see the change in xcode.
If you are using simulator, you can access the changed plist at:
~/Library/Application Support/iPhone Simulator/<Simulator Version>/Applications/<application>/Documents/
One easy way of storing score is to use NSUserDefault, which is a dictionary like persistence store for each application.
Set Score:
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject:#(score)
forKey:#"score"];
[userDefaults synchronize];
Get Score:
int score = [[[NSUserDefaults standardUserDefaults] objectForKey:#"score"] intValue];
UPDATE:
rmaddy mentioned NSUserDefaults supports setInteger:forKey and integerForKey: Therefore you dont need to wrap the score into a NSNumber
When you write an NSDictionary to a plist using writeToFile:, the keys and values in the dictionary must follow strict rules. All keys must be NSString objects and all values must be property values (NSString, NSNumber, NSDate, NSData, etc.).
The problem you have is your dictionary has a key that is an NSNumber, not an NSString.
It appears you actually create the dictionary incorrectly. The syntax is:
#{ key : value, key : value, ... }
Change your code to:
NSDictionary *data = #{ #"bestScore" : bestScoreBox }; // key : value
Side note - your last line should be:
NSLog(#"%#", successful ? #"YES" : #"NO");
It's not good practice to use the ternary operator to run two different commands. It's meant to return one of two values.

Optimum way to make an auto back up of photos on server?

What I've known:
How make requests to server for uploading I will use AFNetworking
How access photos and videos with help of ALAssetsLibrary
I think I must use CoreData to keep info about:last syncing, photos already uploaded, etc. I worked already with coreData it will no be a problem.
My problems are logic, flow how can achieve this auto back up and of course to be optimum(minimum requests, short way). What steps must follow to achieve this scope?
Any thoughts?
I think CoreData is too heavy in this situation. You may want to use plist to store your info data .here are some steps to follow .
After loading image from server, create a dictionary to store the message you want and create another dictionary to store these messages , and use image's url as the key of this dictionary. It might look like this:
imageUrl = {
lastSyncTime = xxxxxxxxxx,
photoUploaded = 0,
}
Create a plist file to save this dictionary:
- (NSString *)filePath:(NSString *) fileName{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
return [documentsDirectory stringByAppendingPathComponent:fileName];
}
[yourImageDictionary writeToFile:[self filePath:#"imageInfo.plist"] atomically:YES];
Read or write your plist file anytime you want:
if ([[NSFileManager defaultManager] fileExistsAtPath:[self filePath:#"imageInfo.plist"]]) {
NSDictionary *imageInfo = [NSDictionary dictionaryWithContentsOfFile:[self filePath:#"imageInfo.plist"]];
}

What else do I need to save a variable into disc?

I'me trying to save a variable into hard drive to load it on my app startup. I do the following:
paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
documentsDirectory = [paths objectAtIndex:0];
votesFile = [documentsDirectory stringByAppendingPathComponent:#"votes.dat"];
Yet, this is creating no file, at least that I can see. When I try to do this:
[votes writeToFile:votesFile atomically:YES]; //votes!=nil
and then
votes = [[NSMutableDictionary alloc] initWithContentsOfFile: votesFile];
it does nothing for me, votes == nil
What am I missing here?
If you are using a NSDictionary with NSStrings as keys, and NSNumbers as values, those classes are compatible with Archiving and Unarchiving pattern, so you can use NSUserDefaults to store your data, and load it the next time you run the application.
To save your data:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:yourVotesDictionary forKey:aKey];
[defaults synchronize]; //This is very important when you finish saving all your data.
To load your data:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSMutableDictionary *votes = [defaults objectForKey:yourNSString];
As you can see, NSUserDefaults is a dictionary, and it behaves like that.
Hope it helps,
have a good day.
There can be various errors using writeToFile:atomically: which is why it returns a BOOL. You should have something like:
if(![votes writeToFile:votesFile atomically:YES]) {
NSLog(#"An error occurred");
}
If you are getting an error there you have an issue with your NSDictionary.

Resources