2
votes

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.

2

2 Answers

2
votes

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.

2
votes
[[detailsDataSource objectAtIndex: detailIndex] setObject:@"Yes" forKey:@"Done"];