Write to string in plist dictionary - iphone

I'm using a plist with structure like this: plist, array, dict key string key string /dict, dict key string key string /dict, /array, /plist.
What I want with the following code it to set the "Done" string's value in current dictionary to "Yes".
But now, the code replaces the whole array of dictionaries with the strings of the current dictionary (with the "Done" key valued "Yes" as it should, though.)
What would be the correct code for what I want?
in DetailViewController.m:
-(IBAction)favoriteButtonPressed:(id)sender
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"Object.plist"];
[[detailsDataSource objectAtIndex: detailIndex] setValue:#"Yes" forKey:#"Done"];
[[detailsDataSource objectAtIndex: detailIndex] writeToFile:path atomically:YES];
}
The detailsDataSource and detailIndex are recieved from TableViewController.m segue if that matters.
TableViewController.m segue part:
detailViewController.detailsDataSource = [[NSArray alloc]initWithArray:objectsArray];
detailViewController.detailIndex = selectedRowIndex.row;
DetailViewController viewDidLoad
if ([[[detailsDataSource objectAtIndex: detailIndex] valueForKey:#"Favorite"] isEqual:#"Yes"]) {
[favoriteButton setImage:[UIImage imageNamed:#"favoritedItem.png"] forState:UIControlStateSelected | UIControlStateHighlighted];
}
districtLabel.text = [[detailsDataSource objectAtIndex: detailIndex] valueForKey:#"District"];
detailsDataSource array is used like this in detailViewController so I cannot change from array to dictionary, must make a mutable copy in that case.

setValue:forKey is not for modifying mutable dictionaries. You should use setObject:forKey. I.e., this:
[[detailsDataSource objectAtIndex: detailIndex] setValue:#"Yes" forKey:#"Done"];
Should be:
[[detailsDataSource objectAtIndex: detailIndex] setObject:#"Yes" forKey:#"Done"];
If that doesn't fix the problem, make sure the dictionary and array are both mutable:
-(IBAction)favoriteButtonPressed:(id)sender {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"Object.plist"];
NSMutableDictionary *mutDict = [NSMutableDictionary dictionaryWithDictionary:[detailsDataSource objectAtIndex:detailIndex]];
[mutDict setObject:#"Yes" forKey:#"Done"];
NSMutableArray *tmpMutArr = [NSMutableArray arrayWithArray:detailsDataSource];
[tmpMutArr replaceObjectAtIndex:detailIndex withObject:[NSDictionary dictionaryWithDictionary:mutDict]]; // make dict immutable before replacing. Casting it ( (NSDictionary *)mutDict ) works too.
[detailsDataSource release], detailsDataSource = nil;
detailsDataSource = [[NSArray alloc] initWithArray:tmpMutArr];
[detailsDataSource writeToFile:path atomically:YES];
}
Also, instead of #"Yes", you can use [NSNumber numberWithBool:YES]:
[mutDict setObject:[NSNumber numberWithBool:YES] forKey:#"Done"];
would generally be better form then using #"Yes".
And:
districtLabel.text = [[detailsDataSource objectAtIndex: detailIndex] valueForKey:#"Yes"];
Should be:
districtLabel.text = [[detailsDataSource objectAtIndex: detailIndex] objectForKey:#"Yes"];
Also noticed that you may have a memory leak with:
detailViewController.detailsDataSource = [[NSArray alloc] initWithArray:objectsArray];
Make sure to autorelease when using property setters that retain.

[[detailsDataSource objectAtIndex: detailIndex] setObject:#"Yes" forKey:#"Done"];

Related

How can I add the following lines to my plist file?

I have seen a lot of tutorials about adding to a plist file but I can't seem to correctly insert nested tags into the plist file.
I want to add the following lines to my Info.plist file
<key>AppTag</key> <array>
<string>hidden</string> </array>
NSMutableDictionary *plist = [[NSDictionary dictionaryWithContentsOfFile:#"/Users/me/Desktop/Info2.plist"] mutableCopy];
[plist setObject:#"AppTag" forKey:#"key"];
[plist setObject:#"hidden" forKey:#"string"];
[plist writeToFile:#"/Users/me/Desktop/Info2.plist" atomically:YES];
[plist release];
You need to set an array of strings as the object for key #"AppTag", like so:
NSArray *strings = #[#"hidden"];
plist[#"AppTag"] = strings;
What you need to do is add strings to your array, and then the array to the dictionary of the file. In the following example, I'm adding some words and their definitions to a file called WordList.plist:
NSArray *values = [[NSArray alloc] initWithObjects:word.name, word.definition, nil];
NSArray *keys = [[NSArray alloc] initWithObjects: NAME_KEY, DEFINITION_KEY, nil];
NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithObjects:values forKeys:keys];
[wordsListArray addObject:dict];
NSString *destinationPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES) lastObject];
destinationPath = [destinationPath stringByAppendingPathComponent:#"WordList.plist"];
[wordsListArray writeToFile:destinationPath atomically:YES];
I hope this helps.
Also, I think this is the part that's not working fine: #"/Users/me/Desktop/Info2.plist"
Try NSLogging.
You can try following code
-(NSString *) datafilepath{
NSArray *path=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documents=[path objectAtIndex:0];
return [documents stringByAppendingFormat:#"/Info2.plist"]; // you can change the path to desktop
}
Under ViewDidLoad or any method
NSString *filepath3=[self datafilepath];
if ([[NSFileManager defaultManager]fileExistsAtPath:filepath3]) {
pricedict=[[NSMutableDictionary alloc]initWithContentsOfFile:filepath3];
}
[pricedict setObject:#"AppTag" forKey:#"key"];
[pricedict setObject:#"hidden" forKey:#"string"];
[pricedict writeToFile:pngfilepath atomically:YES];
Hope this helps.. Happy coding 

How to sort plist by its value

I have Plist with list with List of Dictionaries(item0,item1,item2).and I populate this plist in the Graph..its works fine.and in Plist key (date)-> Value(i store by using NSDate) .Now I need to sort the Plist in such a way that:-
graph should display for only one week.
say if first value is 26-Dec-12 than only upto 1-Jan-13(1 week) values plist should display
.
code :
- (NSArray *)readFromPlist
{
// get paths from root direcory
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
NSString *documentsDirectory = [documentPaths objectAtIndex:0];
NSString *documentPlistPath = [documentsDirectory stringByAppendingPathComponent:#"calori.plist"];
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:documentPlistPath];
valueArray = [dict objectForKey:#"title"];
return valueArray;
}
and
- (void)drawRect:(CGRect)rect {
// Drawing code
CGContextRef _context = UIGraphicsGetCurrentContext();
ECGraph *graph = [[ECGraph alloc] initWithFrame:CGRectMake(10,10, 480, 320)
withContext:_context isPortrait:NO];
NSMutableArray *Array=[NSMutableArray arrayWithArray:[self readFromPlist]];
NSMutableArray *items = [[NSMutableArray alloc] init];
for (id object in [Array reverseObjectEnumerator]){
if ([object isKindOfClass:[NSDictionary class]])
{
NSDictionary *objDict = (NSDictionary *)object;
tempItemi =[[ECGraphItem alloc]init];
NSString *str=[objDict objectForKey:#"title"];
NSLog(#"str value%#",str);
float f=[str floatValue];
NSString*str1=[objDict objectForKey:#"date"];
NSLog(#" str values2-- %#",str1);
tempItemi.isPercentage=YES;
tempItemi.yValue=f;
tempItemi.name=str1;
[items addObject: tempItemi];
}
}
[graph drawHistogramWithItems:items lineWidth:2 color:[UIColor blackColor]];
}
As your requirement is to filter date within 7 days,
I am giving you a logic, try this way:
- (NSArray *)readFromPlistForOneWeek {
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);
NSString *documentsDirectory = [documentPaths objectAtIndex:0];
NSString *documentPlistPath = [documentsDirectory stringByAppendingPathComponent:#"calori.plist"];
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:documentPlistPath];
//loop through each of the item
//and check if <8 then add that keyValue to array
NSMutableArray *tempValueArray=[NSMutableArray new];
for (NSDictionary *subDict in [dict objectForKey:#"title"]) {
// NSLog(#"=> %#",subDict);
NSString *plistDateString=[subDict objectForKey:#"date"];
NSDate *currentDate = [NSDate date];
NSDateFormatter *dateFormatter=[NSDateFormatter new];
[dateFormatter setDateFormat:#"dd-MMM-yy"];
NSDate *plistDate=[dateFormatter dateFromString:plistDateString];
NSString *currentDateString=[dateFormatter stringFromDate:currentDate];
NSTimeInterval secondsBetween = [plistDate timeIntervalSinceDate:currentDate];
NSInteger dateDiff = secondsBetween / 86400;
if( dateDiff<8 ){ //within 0-7 days
[tempValueArray addObject:subDict];
}
}
NSLog(#"valuArray : %#",tempValueArray);
return tempValueArray;
}
Have you tried with NSSortDescriptor?
NSSortDescriptor *sortDesc = [[NSSortDescriptor alloc] initWithKey:#"DATE" ascending:YES selector:#selector(compare:)];
[yourDictionary sortUsingDescriptors:[NSArray arrayWithObject:sortDesc]];
Try this
NSString *path = [[NSBundle mainBundle] pathForResource:#"yourfile" ofType:#"plist"];
NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:path];
// sort it
NSArray *sortedArray = [[myDict allKeys] sortedArrayUsingSelector:#selector(caseInsensitiveCompare:)];
// iterate and print results
for(NSString *key in sortedArray) {
NSLog(#"key=%#,value=%#", key, [dict objectForKey:key]);
}

Searching for objects in array by name

is there a possibility to check for an object in an array by name.
At some point in my app I need to access the plist and pull information stored under an object which I found by its name.
The reason I need to do this is because I don't have the integer number under which where the object is placed in my array.
I have started the usual procedure but i'm not getting anywhere. Maybe its just getting a little too late for me....
This is how my plist looks
Array
Dictionary
title ...
text ...
ect ...
Dictionary
title ...
text ...
ect ...
Dictionary
title ...
text ...
ect ...
My code so far isn't helping at all. I'm definitely doing something wrong.
-(NSString*)nameFromPlist:(NSString*)name {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *writableDBPath = [documentsDirectory stringByAppendingPathComponent:#"Orte.plist"];
_regionArray = [NSArray arrayWithContentsOfFile:writableDBPath];
NSString *string = [[NSString alloc]init];
for(NSDictionary *dict in _regionArray) {
string = [[dict objectForKey:name] valueForKey:#"title"];
}
return [NSString stringWithFormat:#"%#",string];
}
My string is just returning null.
Any ideas anyone?
Thanks a lot!
ANSWER:
Here is the code for everyone:
-(NSString*)nameFromPlist:(NSString*)name {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *tmpFileName = [[NSString alloc] initWithFormat:#"Orte.plist"];
NSString *path = [documentsDirectory stringByAppendingPathComponent:tmpFileName];
NSString *string;
NSMutableArray *array = [NSMutableArray arrayWithContentsOfFile:path];
NSDictionary *dict = [[NSDictionary alloc] init];
NSString *title;
for (int i=0; i<[array count]; i++) {
dict = [array objectAtIndex:i];
title = [dict valueForKey:#"title"];
if([title isEqualToString:name]) {
string = [dict valueForKey:#"title"];
NSLog(#"Titel: %#", string);
}
}
return [NSString stringWithFormat:#"%#",string];
}
Thank a lot everyone!
First you don't need to alloc the NSString, 'cause you'll get a different one from valueForKey.
Then if I understood right what you want to get a better code may be something that make use of NSPredicate or the block-based indexOfObjectPassingTest. Both iterate across the array and perform a test on the elements to get you the matching elements (or the index of them).
NSString* plistPath = [[NSBundle bundleForClass:[self class]] pathForResource:#"<PlistFileName>" ofType:#"plist"];
NSArray *array = [[NSArray alloc] initWithContentsOfFile:plistPath];
NSMutableArray* titles = [[NSMutableArray alloc] init];
for (NSDictionary* d in array)
[titles addObject:[d objectForKey:#"title"]];
NSLog(#"Object found at index %i", [a indexOfObject:#"<Your object name>"]);
Make sure you're testing against NSNotFound for failure to locate, and not (say) 0.

how to write plist array of dictionary objects..dynamically and populating the tableview

m working with plist and i am new to it..
I want to save two type of values,these two are labels,i.e
label1
label2
so for that i tried to write the code but was able to save only for one
label i.e label1..in a plist and then populate it into the table so i got one value on
cell.textlabel.text = label1.text
but i need this also..
cell.detailedlabel.text = label2.text
so below is my code.. to save label1.text
-(IBAction) myBrand:(id) sender
{
NSLog(#"mylist Clicked");
NSMutableArray *array = [[NSMutableArray alloc] init];
NSArray *paths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docsDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES) objectAtIndex:0];
NSString *plistPath = [docsDir stringByAppendingPathComponent:#"Data.plist"];
[array addObjectsFromArray:[NSArray arrayWithContentsOfFile:plistPath]];
[array addObject:searchLabel.text];
[array writeToFile:plistPath atomically: TRUE];
}
now if i want o save one more label..in the array and populate it on cells detailedlabel..how shall i proceed..please help me out..
Hi friends..I want o have something like this....
NSMutableArray *array = [[NSMutableArray alloc] init];
// get paths from root direcory
NSArray *paths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);
// get documents path
NSString *docsDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES) objectAtIndex:0]; // get the path to our Data/plist file
NSString *plistPath = [docsDir stringByAppendingPathComponent:#"Data.plist"];
//This copies objects of plist to array if there is one
[array addObjectsFromArray:[NSArray arrayWithContentsOfFile:plistPath]];
//[array addObject:entity];
[array insertObject:entity atIndex:0];
[array insertObject:category atIndex:0];
NSDictionary *plistDict = [NSDictionary dictionaryWithObjects: [NSArray arrayWithObjects: entity, category, nil] forKeys:[NSArray arrayWithObjects: #"Entity", #"Category", nil]];
Regards
Ranjit
go through the portion of the code below which will solve your problem of storing both label values in plist...
NSMutableArray *data = [[NSMutableArray alloc] init];
NSMutableDictionary* newDict = [[NSMutableDictionary alloc] init];
[newDict setValue:label1.text forKey:labell]; //forKey identify the name of the array element in dictionary for plist
[newDict setValue:label2.text forKey:label2];
[data addObject:newDrink];
[newDict release];

Adding an object with "text"

I'm stumped or just not finding info I need, I have an object that I want to save in an array when they select "saveDataround" button, however I can't seem to figure out how to populate the object with the text "Round": I'm getting an "Expected identifier" and "Expected , ;" errors on the first and second lines of code. Thanks in advance.
[NSString *roundChoice = [NSString stringWithFormat:#"Round"];
self.round.text = roundChoice;]
- (IBAction)saveDataround {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *recipient = [NSString stringWithFormat:#"%#/arrayChoiceRound", documentsDirectory];
NSMutableArray *array = [[NSMutableArray alloc] init];
[array addObject:round.text];
[array writeToFile:recipient atomically:NO];
}
Where are the first two lines of code implemented? What are they supposed to do?
Here's how I would modify the above code without more info:
// remove "[" from start of line & no need to use stringWithFormat here
NSString *roundChoice = #"Round";
// remove "]" from end of line
self.round.text = roundChoice;
- (IBAction)saveDataround {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
// use stringByAppendingPathComponent here
NSString *recipient = [documentsDirectory stringByAppendingPathComponent:#"arrayChoiceRound"];
NSMutableArray *array = [[NSMutableArray alloc] init];
// use self here (not required)
[array addObject:self.round.text];
[array writeToFile:recipient atomically:NO];
// release the array
[array release];
}