Append New Input to plist in Documents Folder - ios

After much searching of SO I've been able to come up with code to correct previous failures. What I am trying to accomplish is accepting user input from a UITextField and add that input to my TableView, which is populated from a plist. The root value of my plist is dictionary and I would like to keep it as such. My problem is when writeToFile is called, I'm completely over writing the existing values instead of inserting, adding or appending to the existing data. It doesn't appear that my attempt to combine the two dictionaries is working, since only the new value is being stored to the plist. Any insight as to where I'm going wrong? The following code is what I have
//////////********** Add New Cell When OK is Chosen
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
UITextField *newDevice = [alertView textFieldAtIndex:0];
NSLog(#"newDevice - %#",newDevice.text);
if (alertView.tag == 1 && buttonIndex == 1){
NSMutableDictionary *input = [[NSMutableDictionary alloc]init];
[input setObject:[NSArray arrayWithObject:newDevice.text] forKey:#"Room"];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"Test.plist"];
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] initWithContentsOfFile:path];
// Combine the two Dictionaries to create one
[dictionary addEntriesFromDictionary:input];
// Write Combined Dictionary to plist
[dictionary writeToFile:path atomically:YES];
// Add Newly Created text to Table because reload table doesn't do it
[myTableData addObject:newDevice.text];
// Reload Table Data even though it seems useless
[myTable reloadData];
}
}

I guess you overwrote the values of the key Room.
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"Test.plist"];
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] initWithContentsOfFile:path];
// Get exist input from plist
NSMutableArray *inputFromPlist = dictionary[#"Room"];
// add new object to input
[inputFromPlist addObject:newDevice.text];
// set Room with modified object
[dictionary setObject:inputFromPlist forKey:#"Room"];
// Write Combined Dictionary to plist
[dictionary writeToFile:path atomically:YES];
// do something after saving plist ...

Related

removeObjectForKey doesn't remove value from .plist

I am developing iPhone app in which i have TableView,
What i want to do is On click of UITableViewCell i want to remove this values from plist, MOBILES.Brand.2 and MOBILES.Brand.5 if they exist in .plist if they doesn't exist in .plist then i want to add it to my .plist
Here is the structure of my .plist:
:
Here is my code snippet:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
plistPath = [self getPlistPath];
//PlistDict is mutableDictionary contains the keys and values of .plist (of above image)
if ([PlistDict valueForKeyPath:#"MOBILES.Brand.2"] != nil) { //if key and it's value exists in Filter.plist
//Delete Key from .plist...
NSMutableDictionary *savedStock = [[NSMutableDictionary alloc] initWithContentsOfFile:plistPath];
[savedStock removeObjectForKey:#"MOBILES.Brand.2"];
[savedStock removeObjectForKey:#"MOBILES.Brand.5"];
[savedStock writeToFile:plistPath atomically:YES];
}else{
//Add Key to .plist
NSMutableDictionary *data = [[NSMutableDictionary alloc] initWithContentsOfFile:plistPath];
[data setValue:#"251" forKeyPath:#"MOBILES.Brand.2"];
[data setValue:#"298" forKeyPath:#"MOBILES.Brand.5"];
[data writeToFile:plistPath atomically:YES];
}
}
-(NSString*)getPlistPath{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"Filter.plist"];
PlistDict = [NSMutableDictionary dictionaryWithContentsOfFile:path];
return path;
}
after writing above code snippet it doesn't remove the keys from .plist but it adds the key successfully if not existed.
Where i am doing mistake ? please help and thanks in advance.
The problem is you are trying to remove using the NSMutableDictionary keypath directly using removeObjectForKey that requires the exact key not keypath and you are supplying a keypath. Use the following NSMutableDictionary Category taken from here
#interface NSMutableDictionary (Additions)
- (void)removeObjectForKeyPath: (NSString *)keyPath;
#end
#implementation NSMutableDictionary (Additions)
- (void)removeObjectForKeyPath: (NSString *)keyPath
{
// Separate the key path
NSArray * keyPathElements = [keyPath componentsSeparatedByString:#"."];
// Drop the last element and rejoin the path
NSUInteger numElements = [keyPathElements count];
NSString * keyPathHead = [[keyPathElements subarrayWithRange:(NSRange){0, numElements - 1}] componentsJoinedByString:#"."];
// Get the mutable dictionary represented by the path minus that last element
NSMutableDictionary * tailContainer = [self valueForKeyPath:keyPathHead];
// Remove the object represented by the last element
[tailContainer removeObjectForKey:[keyPathElements lastObject]];
}
#end
It should work for you.
Method - 2
If the above doesn't work, you can do an iteration of your dictionary, and specifically delete the object for the key.. Try
NSMutableDictionary *savedStock = [[NSMutableDictionary alloc] initWithContentsOfFile:plistPath];
NSMutableDictionary *brand=[[savedStock objectForKey:#"MOBILES"] objectForKey:#"Brand"];
[brand removeObjectForKey:#"2"];
[brand removeObjectForKey:#"5"];
Cheers.

Append items to an existing key in NSDictionary saved in a plist

How can I append values to an existing key in NSDictionary from a plist?
What I have is basically a plist saved in disc with a few keys and values, the keys are the names of some students with one initial value. What I’m trying to do that doesn't work is to append more items to existing keys/Students by reading the plist, adding it to a temporary NSDictionary, appending a temporary array to an existing key in the plist but when I save the plist back it doesn’t work, it only saves the last two items and basically deletes the initial value for that key.
Here is the code that I’m using…
- (IBAction)testing:(id)sender
{
NSArray *dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = [dirPaths objectAtIndex:0];
NSString *fullPath = [documentsPath stringByAppendingPathComponent:#"studentsRecords.plist"];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:fullPath];
if(fileExists)
{
NSMutableDictionary *dictionaryRecords = [[NSMutableDictionary alloc]initWithContentsOfFile:fullPath];
NSLog(#"Items for Nathan: %#",[dictionaryRecords objectForKey:#"Nathan"]);// here the output is, Items for Nathan: Ruler
// which make sense since I only had one initial record for Nathan in my plist,
// Here, I want to add two more items to the key Nathan by appending an arry to
// NSMutableDictionary (dictionaryRecords) but it doesnt work
NSArray *tempArray = #[#"NoteBook", #"Pencil"];
[dictionaryRecords setObject:tempArray forKey:#"Nathan"];
[dictionaryRecords writeToFile:fullPath atomically:YES];
// when I check the plist after saving this, I only see the last two values, NoteBook and Pencil
// instead of the three that I'm expecting, Ruler, NoteBook and Pencil
}
}
What am I missing here?
Thanks a lot in advance.
[dictionaryRecords setObject:tempArray forKey:#"Nathan"] replaces whatever the previous value was with tempArray.
If you want to add to the existing array, you have to retrieve it, make a mutable copy, and append to it.
Here is how I made it work. I hope I didn't over complicated things here but for some reason I had to use two arrays, an NSArray and an NSMutableArray, I would think that the NSMutableArray would be enough but it didn't work.
- (IBAction)testing:(id)sender
{
// get directory path
NSArray *dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = [dirPaths objectAtIndex:0];
// create plist
NSString *fullPath = [documentsPath stringByAppendingPathComponent:#"studentsRecords.plist"];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:fullPath];
// if file exists create dictionary
if(fileExists)
{
// add items from plist to dictionary
NSDictionary *dictionaryExistingRecords = [[NSDictionary alloc]initWithContentsOfFile:fullPath];
// make a copy if dictinary with existing items
NSMutableDictionary *dictionaryNewRecords = [dictionaryExistingRecords mutableCopy];
// array to hold existing values from a spcecified key
NSArray *arrayWithExistingKey = [dictionaryExistingRecords objectForKey:#"Nathan"];
// mutable array to add existing and be able to insert new items
NSMutableArray *arrayOldAndNewItems = [NSMutableArray arrayWithArray:arrayWithExistingKey];
// insert new items to array
[arrayOldAndNewItems addObject:#"Snow Pans"];
// add old and new items to specified key
[dictionaryNewRecords setObject:arrayOldAndNewItems forKey:#"Nathan"];
// save new records to plist
[dictionaryNewRecords writeToFile:fullPath atomically:YES];
}
}
#end

Plist dicionaries keys

I am using this code to add content into a plist :
//////////// Save data into plist /////////////////
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"datatesting.plist"];
NSLog(#"path='%#'",path);
NSFileManager *nfm = [[NSFileManager alloc] init];
if([nfm fileExistsAtPath:path])
{
// if file exists, get its contents, add more entries and write back
NSMutableArray *array = [[NSMutableArray alloc] initWithContentsOfFile:path];
NSArray *keys = [NSArray arrayWithObjects:#"Title",#"Description",#"Coordinate",nil];
[array addObject:[NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:[NSString stringWithFormat:#"%#",titlestring],[NSString stringWithFormat:#"%#",descriptionstring],[NSString stringWithFormat:#"%#",coordinadastring], nil] forKeys:keys]];
NSLog(#"modified array=%#",array);
BOOL ok = [array writeToFile:path atomically:YES];
if(!ok){
NSLog(#"Unable to write appended file");
return;
}
} else {
// if file doesn't exist, create a new one
NSMutableArray *array = [[NSMutableArray alloc] init];
NSArray *keys = [NSArray arrayWithObjects:#"Title",#"Description",#"Coordinate",nil];
[array addObject:[NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:[NSString stringWithFormat:#"%#",titlestring],[NSString stringWithFormat:#"%#",descriptionstring],[NSString stringWithFormat:#"%#",coordinadastring], nil] forKeys:keys]];
NSLog(#"new array=%#",array);
BOOL ok = [array writeToFile:path atomically:YES];
if(!ok){
NSLog(#"Unable to write new file");
return;
}
}
Now I am having issues in using the content of the plist. So my two questions are :
- What is the Keys of the dictionaries of the current plist ?
- What is the way to read the content in a Tableview ?
You have an array of dictionaries. You need to iterate on the contents of the array, then look at each dictionary. You can do this with block enumerators or the older for() style. I'll use the latter now as you may not know blocks.
NSArray *array = ...; // read in the array from the file
for(NSDictionary *dict in array) {
NSString *title = [dict objectForKey:#"Title"];
... etc
}
When you want to show this data in a tablview, the number of rows is the number of dictionaries (ie [array count]). If you wanted to show just the title for each cell, you would get the cell row number, then get the dictionary by [array objectAtIndex:cellRow]), then pull out the title as above.

Load data from plist to tableview [duplicate]

This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
How to populate UITableView with plist
I save data to plist like this:
- (IBAction)save:(id)sender
{
NSArray *paths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = [paths objectAtIndex:0];
NSString *plistPath = [documentsPath stringByAppendingPathComponent:#"data.plist"];
NSMutableArray *data = [NSMutableArray arrayWithContentsOfFile:plistPath];
if (nil == data) {
data = [[NSMutableArray alloc] initWithCapacity:0];
}
else {
[data retain];
}
NSMutableDictionary *array = [[NSMutableDictionary alloc]init];
[array setObject:label1.text forKey:#"Test1"];
[array setObject:label2.text forKey:#"Test2"];
[array setObject:label3.text forKey:#"Test3"];
[array setObject:label4.text forKey:#"Test4"];
NSLog(#"%#", array);
[data addObject:array];
[array release];
[data writeToFile:plistPath atomically: TRUE];
[data release];
}
NSLog:
2012-07-01 18:52:19.566 testapp[22651:707] {
Test1 = 40;
Test2 = 102;
Test3 = 153;
Test4 = 255;
}
How can I load saved data to uitableview?
To read it, do this:
NSMutableDictionary* plistDict = [[NSMutableDictionary alloc] initWithContentsOfFile:plistPath];
You should then be able to read the values for all the keys like this:
NSString *myValue = [plistDict objectForKey:#"someKey"];
edit:
After rereading your code it seems like you might be doing something you don't want to do. Your current plist structure is a top level array that adds a dictionary to itself every time you invoke "save". Is this what you're trying to do? If so, what represents a cell in your table, an index in the array?
If so, then you want to do
// top level array
NSMutableDictionary* plistArray = [[NSMutableDictionary alloc] initWithContentsOfFile:plistPath];
// individual dictionary at one array index (such as indexPath.row in cellForRowAtIndexPath)
NSMutableDictionary *dictionary = [plistArray objectAtIndex:yourIndex];
In any case, the object you have named "array" is actually a dictionary so you should rename it (or change it to be an array if that's what you want).

Saving data to plist per object or person

I am trying to save data to the plist in my app per person, but it save it to everyone, so for example if I have a field for eye color and I enter Brown in the textfield for John Doe, it save Brown for everyone else as well, is there a way to save this info per person in the app instead using plist? I have had no luck trying:
-(NSString *)pathofFile{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docsfolder = [paths objectAtIndex:0];
return [docsfolder stringByAppendingFormat:#"data.plist"];
}
Here is the code I have in my view did load:
- (void)viewDidLoad {
[self loadPerson];
[super viewDidLoad];
NSString *filepath = [self pathofFile];
if ([[NSFileManager defaultManager]fileExistsAtPath:filepath]) {
NSArray *array = [[NSArray alloc]initWithContentsOfFile:filepath];
Drinfo.text = [array objectAtIndex:0];
[array release];
}
UIApplication *app = [UIApplication sharedApplication];
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(applicationWillTerminate:) name: UIApplicationWillTerminateNotification object:app];
and here is what I have as part of my saveperson method:
NSMutableArray *array = [[NSMutableArray alloc]init];
[array addObject:self.Drinfo.text];
[array writeToFile:[self pathofFile] atomically:YES];
[array release];
You could use a plist just create a NSDictionary for each person inside the plist and add the colour string to that. The steps would be something like
Open up the plist from file, set it to be a NSDictionary and make sure its a mutable copy.
Create a new NSMutableDictionary and add any attributes to that e.g. eye colour.
Add that mutable dictionary to your plist dictionary with the key set to the persons name
Save the plist

Resources