writeToFile NSDictionary not saving to plist correctly - ios

I have a custom plist that I am using to populate UItableViewCells with, I am able to read them perfectly, however when I try to write to my custom plist file it never changes.
NSString *errorDesc = nil;
NSString * plistPath = [[NSBundle mainBundle] pathForResource:#"AdvanceSearchPrefrences" ofType:#"plist"];
NSMutableDictionary *advPrefs = [NSMutableDictionary dictionaryWithContentsOfFile:plistPath];
[advPrefs setObject:cell.textLabel.text forKey:#"Manuf"];
[advPrefs setObject:selRow forKey:#"ManufNum"];
NSData *plistData = [NSPropertyListSerialization dataFromPropertyList:advPrefs format:NSPropertyListXMLFormat_v1_0 errorDescription:&errorDesc];
[plistData writeToFile:plistPath atomically:YES];
NSString * plistPath2 = [[NSBundle mainBundle] pathForResource:#"AdvanceSearchPrefrences" ofType:#"plist"];
NSMutableDictionary *advPrefs2 = [NSMutableDictionary dictionaryWithContentsOfFile:plistPath2];
The advPrefs shows the new values and advPrefs2 shows the old values.

You can't directly save over your plist, but what you can do is create a copy and save that to NSUserDefaults.
On the initial load you do something like this in your AppDelegate. This will copy your plist into something you can edit and save:
NSString * plistPath = [[NSBundle mainBundle] pathForResource:#"AdvanceSearchPrefrences" ofType:#"plist"];
NSMutableDictionary *advPrefs = [NSDictionary dictionaryWithContentsOfFile:plistPath];
[[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:advPrefs] forKey:#"plist"];
[[NSUserDefaults standardUserDefaults] synchronize];
In your class that you want to fetch the copied plist, you can call something like this:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *data = [defaults objectForKey:#"plist"];
NSMutableDictionary *advPrefs = [[NSKeyedUnarchiver unarchiveObjectWithData:data]mutableCopy];
Then make your changes
[advPrefs setObject:cell.textLabel.text forKey:#"Manuf"];
[advPrefs setObject:selRow forKey:#"ManufNum"];
And then save them to NSUserDefaults
[[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:advPrefs] forKey:#"plist"];
[[NSUserDefaults standardUserDefaults] synchronize];
I had this same problem with my app and this is how I fixed it. Hope this works for you too

Read data:
NSData *data;
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:#"AdvanceSearchPrefrences.plist"];
if (filePath) {
data = [[NSString stringWithContentsOfFile:filePath
encoding:NSUTF8StringEncoding
error:&error]
dataUsingEncoding:NSUTF8StringEncoding];
// use data here....
}
Write data:
NSString *documentDirectoryPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *path = [documentDirectoryPath stringByAppendingPathComponent:#"AdvanceSearchPrefrences.plist"];
if ([dataToBeWritten writeToFile:path
atomically:YES
encoding:NSUTF8StringEncoding
error:&error]) {
// data is written
}

Related

Write NSArray to plist file

I have a code to get the data of a plist file and a code to write data to a plist file. Now the things is, that it add's the readed data in one array (See images).
I want it in different arrays (See green image)
HERE IS MY CODE:
- (void)WriteData {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"MuziekList.plist"];
if ([fileManager fileExistsAtPath:path] == NO) {
NSString *resourcePath = [[NSBundle mainBundle] pathForResource:#"MuziekList" ofType:#"plist"];
[fileManager copyItemAtPath:resourcePath toPath:path error:&error];
}
//_______________________________________________________________________________________________________________
NSMutableDictionary *savedStock = [[NSMutableDictionary alloc] initWithContentsOfFile: path];
//load from savedStock example int value
NSArray *NummerTexts;
NummerTexts = [savedStock objectForKey:#"Nummers"];
NSString *NummerTextsR = [[NummerTexts valueForKey:#"description"] componentsJoinedByString:#" - "];
NSArray *ArtiestTexts;
ArtiestTexts = [savedStock objectForKey:#"Artiesten"];
NSString *ArtiestTextsR = [[ArtiestTexts valueForKey:#"description"] componentsJoinedByString:#" - "];
//_______________________________________________________________________________________________________________
NSUserDefaults *CurrentVideoNummerResult = [NSUserDefaults standardUserDefaults];
NSString *CurrentVideoNummer = [CurrentVideoNummerResult stringForKey:#"CurrentVideoNummer"];
NSUserDefaults *CurrentVideoArtiestResult = [NSUserDefaults standardUserDefaults];
NSString *CurrentVideoArtiest = [CurrentVideoArtiestResult stringForKey:#"CurrentVideoArtiest"];
/*
NSUserDefaults *CurrentVideoIDResult = [NSUserDefaults standardUserDefaults];
NSString *CurrentVideoID = [CurrentVideoIDResult stringForKey:#"CurrentVideoID"];
*/
NSMutableDictionary *plist = [[NSDictionary dictionaryWithContentsOfFile:path] mutableCopy];
NSMutableArray *newArray = [[NSMutableArray alloc] init];
NSMutableArray *newArray2 = [[NSMutableArray alloc] init];
newArray = [NSMutableArray arrayWithObjects:CurrentVideoNummer, NummerTextsR, nil];
[plist setObject:newArray forKey:#"Nummers"];
newArray2 = [NSMutableArray arrayWithObjects:CurrentVideoArtiest, ArtiestTextsR, nil];
[plist setObject:newArray2 forKey:#"Artiesten"];
[plist writeToFile:path atomically:YES];
}
Click link for images
https://www.dropbox.com/sh/wrk8h8cnwye8myx/AADl4omkGdl3S4ESXv6NbymVa?dl=0
Your question and problem are confusing. Maybe this will help:
Your code reads your current array (NummerTexts), flattens that array to a single string (NummerTextsR), gets a second string (CurrentVideoNummer), then builds a two-element array (newArray).
Your question appears to be why do you get a two-element array...?
If you don't want to flatten your original array don't do so, just make a mutable copy of it, something like:
NSMutableArray *existingTexts = [[NummerTexts valueForKey:#"description"] mutableCopy];
add your new element:
[existingTexts addObject:currentVideoNummer];
and write it back like you already are.
HTH
BTW Do not start local variable names with an uppercase letter, this goes against convention and is why the syntax highlighting in your question is all wrong.

Saving objects to the app, IOS

My app in development is related to survey questions. (fun ones, not boring ones!) I want to create a tier system for each question relative to the user, each time they answer a specific question I want to associate a value to that question for that user, identifying how many times they've answered it.
I believe the way I need to achieve this is NSMutableDictionary and NSUserDefaults. This is a simplified version of my code:
NSMutableDictionary *questionTierDictionary = [[NSMutableDictionary alloc]init];
[[NSUserDefaults standardUserDefaults] objectForKey:#"questionTiers"];
[questionTierDictionary setObject:[NSNumber numberWithInt:4] forKey:#(2)];
[[NSUserDefaults standardUserDefaults] synchronize];
NSLog(#"%#", questionTierDictionary);
Does this code save this data indefinitely to the app, or does it disappear once the user has closed the app? If so, do you have any suggestions on how I can easily test to see if the data was stored?
sandbox path :
~~ Documents:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docDir = [paths objectAtIndex:0];
~~~ Caches:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cachesDir = [paths objectAtIndex:0];
~~~ tmp:
NSString *tmpDir = NSTemporaryDirectory();
~~~ home sandbox:
NSString *homeDir = NSHomeDirectory();
~~~ for pic :
NSString *imagePath = [[NSBundle mainBundle] pathForResource:#"apple" ofType:#"png"];
UIImage *appleImage = [[UIImage alloc] initWithContentsOfFile:imagePath];
Example:
NSFileManager* fm=[NSFileManager defaultManager];
if(![fm fileExistsAtPath:[self dataFilePath]]){
//
[fm createDirectoryAtPath:[self dataFilePath] withIntermediateDirectories:YES attributes:nil error:nil];
//
NSArray *files = [fm subpathsAtPath: [self dataFilePath] ];
//
NSData *data = [fm contentsAtPath:[self dataFilePath]];
//
NSData *data = [NSData dataWithContentOfPath:[self dataFilePath]];
}
I hope I could help you!
NSUserDefaults save data permanently in you application directory till you remove it manually... to save a object in NSUserDefaults code like this
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:#"yourObject",#"yourKey", nil];
[[NSUserDefaults standardUserDefaults]setObject:dict forKey:#"dict"];
//fetch Like this
NSDictionary *dict1 = [[NSUserDefaults standardUserDefaults] objectForKey:#"dict"];

Create blank plist programmatically (in DocumentsDirectory)

Normally I save data to a plist (just data that I don't really care if a JailBroken phone hacked, like users preferences and stuff) except when the user first launches the app I create the plist like so:
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *pathFirstTime = [documentsDirectory stringByAppendingPathComponent:#"FirstTime.plist"];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath: pathFirstTime])
{
NSString *bundleFirstTime = [[NSBundle mainBundle] pathForResource:#"FirstTime" ofType:#"plist"];
[fileManager copyItemAtPath:bundleFirstTime toPath:pathFirstTime error:&error];
}
So I create a blank plist file in xcode and put it in the bundle and the first time the user launches the app it copies it to the documentsDirectory...
Is there anyway I can create the blank plist file in objective-c the first time that way I don't actually have to create one in Xcode and have it in the bundle but it will just get created automatically the first time the user launches the app...
Basically just avoiding this code: [fileManager copyItemAtPath:bundleFirstTime toPath:pathFirstTime error:&error];
[#{} writeToFile: pathFirstTime atomically: NO];
Create an NSArray or NSDictionary instance and use writeToFile:atomically:.
remove your whole code, this will do the trick
if(![[NSUserDefaults standardUserDefaults] objectForKey:#"FirstRun"]){
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *pathFirstTime = [documentsDirectory stringByAppendingPathComponent:#"MyPlistFile.plist"];
[#{} writeToFile: pathFirstTime atomically: YES];
[[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithBool:NO] forKey:#"FirstRun"];
}
Want to add a new record ?
NSString *pathFirstTime = [documentsDirectory stringByAppendingPathComponent:#"MyPlistFile.plist"];
NSMutableDictionary *mdic = [[NSMutableDictionary alloc] initWithDictionary:[NSDictionary dictionaryWithContentsOfFile:pathFirstTime]];
[mdic setObject:[NSNumber numberWithInt:3] forKey:#"user-selected-color-scheme"];
[mdic writeToFile: pathFirstTime atomically: YES];
Read the plist file later ?
NSString *pathFirstTime = [documentsDirectory stringByAppendingPathComponent:#"MyPlistFile.plist"];
NSMutableDictionary *mdic = [[NSMutableDictionary alloc] initWithDictionary:[NSDictionary dictionaryWithContentsOfFile:pathFirstTime]];
NSLog(#"%#", mdic);

How to save content of TextField to plist

I want to save the content of TextFields in plist with corresponding Key-Values pair.
Like Password field should be saved with the Key-Password and Value-(entered in textField).
How can I do that?
and want to access it in some other class. Can I do it? If yes, then how?
Adding Stuff into plist is easy. Full working code follows which adds a persons contact info into a plist -
// get paths from root direcory
NSArray *paths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);
// get documents path
NSString *documentsPath = [paths objectAtIndex:0];
// get the path to our Data/plist file
NSString *plistPath = [documentsPath stringByAppendingPathComponent:#"Data.plist"];
// set the variables to the values in the text fields
self.personName = nameEntered.text;
self.phoneNumbers = [[NSMutableArray alloc] initWithCapacity:3];
[phoneNumbers addObject:homePhone.text];
[phoneNumbers addObject:workPhone.text];
[phoneNumbers addObject:cellPhone.text];
// create dictionary with values in UITextFields
NSDictionary *plistDict = [NSDictionary dictionaryWithObjects: [NSArray arrayWithObjects: personName, phoneNumbers, nil] forKeys:[NSArray arrayWithObjects: #"Name", #"Phones", nil]];
NSString *error = nil;
// create NSData from dictionary
NSData *plistData = [NSPropertyListSerialization dataFromPropertyList:plistDict format:NSPropertyListXMLFormat_v1_0 errorDescription:&error];
// check is plistData exists
if(plistData)
{
// write plistData to our Data.plist file
[plistData writeToFile:plistPath atomically:YES];
}
else
{
NSLog(#"Error in saveData: %#", error);
[error release];
}
[source]
You can save the content of textField to Plist in the following manner :
NSMutableDictionary *_plistDict = [NSMutableDictionary dictionaryWithContentsOfFile:pListPath];
[_plistDict setValue:textField.text forKey:#"Password"];
[_plistDict writeToFile:pListPath atomically:YES];
If you want to retrieve that value from pList , You can use the following code :
NSMutableDictionary *_plistDict = [NSMutableDictionary dictionaryWithContentsOfFile:pListPath];
NSString *status = [NSString stringWithFormat:#"%#",[_plistDict objectForKey:#"Password"]];
Yes, Take a NSMutableDictionary add values of UITextFeild property of text in in keys of Dictionary. Like
NSMutableDicitonary * dictionary = [[NSMutableDictionary alloc] init];
[dictionary setObject:textfield.text forKey:#"username"];
[dictionary setObject:textfield.text forKey:#"password"];
Save Dictionary in plist and use it where ever it requires.
NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *aFilePath = [NSString stringWithFormat:#"%#/plistName.plist", aDocumentsDirectory];
NSMutableArray *plistArray = [[NSMutableArray alloc] initWithContentsOfFile:aFilePath];
NSMutableDictionary *newComment = [NSMutableDictionary dictionary];
[newComment setValue:userName.text forKey:#"username"];
[newComment setValue:password.text forKey:#"password"];
[plistArray addObject:newComment];
[plistArray writeToFile:filePath atomically:YES];
Best practice would be saving these info in NSUserDefaults instead of a plist. NSUserDefautls can be accessed from anywhere in your project.
Saving:
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject:[yourTextfield text] forKey:#"password"];
Retrieving:
NSString *myPassword = [[NSUserDefaults standardUserDefaults] objectForKey:#"password"];

iOS:Read and Write into Plist

I want to save the token from from the server into a plist. I am not sure If I have to create a plist firs or it can automatically get created with the following code in my Document directroy. However, I am not able to create a plist and write my dictionary into it.
Here is my code
-(void)writeToPlist:(NSString*)value forkey:(NSString *)key
{
NSLog(#"Write plist here");
//NSError *error;
NSArray *paths=NSSearchPathForDirectoriesInDomains( NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDirectory=[paths objectAtIndex:0];
NSString* path=[documentDirectory stringByAppendingFormat:#"Util.plist"];
NSLog(#"The path is %#",path);
NSFileManager *fileManager=[NSFileManager defaultManager];
NSMutableDictionary *data;
if(![fileManager fileExistsAtPath:path])
{
path=[[NSBundle mainBundle]pathForResource:#"Util" ofType:#"plist"];
}
[data setObject:value forKey:key];
[data writeToFile:path atomically:YES];//will it create the plist?
}
why don't you save it using NSUserDefaults?
here's an example code :
NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];
if([standardUserDefaults objectForKey:#"your-key-goes-here"] == nil) //this means you don't have that key
{[standardUserDefaults setValue:#"your-value-goes-here" forKey:#"your-key-goes-here"];}
[standardUserDefaults synchronize];
don't forget to synchronize in the final.
and when you need the data you need to call standartUserDefaults's :valueForKey method.
hope this helps..
I found a way to easily create a plist file programatically, this works for me:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingString:#"/myFile.plist"];
if (![[NSFileManager defaultManager] fileExistsAtPath:path]){
NSDictionary *emptyDic = [NSDictionary dictionary];
[emptyDic writeToFile:path atomically:YES];
}
Change what is inside the if statement and it will work.

Resources