views:

1361

answers:

2

I have the following code which should update a value in NSUserDefaults:

- (id) createBoardWithTitle:(NSString *)pTitle withScores:(NSArray *)pScores andNames:(NSArray *)pNames andDisplayStrings:(NSArray *)pStrings orderBy:(NSString *)pOrder ofType:(NSString *)pType
{

    if((self == [super init]))
    {

     boardEntries = [NSMutableArray arrayWithCapacity:10];

     // Build the data

            for(...){
               // populate boardEntries
            }


     // create an Dictionary to save
     NSDictionary *savedData = [NSDictionary dictionaryWithObjectsAndKeys:pType, @"type", pOrder, @"order", boardEntries, @"entries", nil];

            // Load the old boards
     NSDictionary *existingBoards = [[NSUserDefaults standardUserDefaults] objectForKey:@"BlockDepotLeaderboards"];

            // Create a mutable dictionary to replace the old immutable dictionary
     NSMutableDictionary *newBoards = [NSMutableDictionary dictionaryWithCapacity:[existingBoards count]+1];

            // transfer the old dictionary into the new dictionary
     [newBoards addEntriesFromDictionary:existingBoards];

            // add the new board to the new dictionary
     [newBoards setObject:savedData forKey:pTitle];

            // check to make sure it looks like it should by eye
     NSLog(@"New Boards: %@", newBoards);

            // Replace the old date in NSUserdefaults
     [[NSUserDefaults standardUserDefaults] setObject:newBoards forKey:@"BlockDepotleaderboards"];
            // Update: Do I really need to call this?
     [[NSUserDefaults standardUserDefaults] synchronize];

            // Check to make sure it looks as it should by eye
     NSLog(@" Defaults--- %@", [[NSUserDefaults standardUserDefaults] objectForKey:@"BlockDepotLeaderboards"]);
    }

    return self;

}

As far as I can tell, that's the pertinent code. It's probably "wordier" than it needs to be perhaps. But as I understand it, anything returned from NSUserDefaults will be immutable, so I have to recreate it as a Mutable object, add what needs adding then replace the object in NSUserDefaults. And I think what I'm trying above should work.

the output for NSLog(@"New Boards: %@", newBoards) id

New Boards: {
    "Marathon: Times" =     {
        entries =         (
                        {
                displayString = "10:00";
                name = "Tom Elders";
                score = 600;
            },
                        {
                displayString = "10:30";
                name = "A.R. Elders";
                score = 630;
            },
                        {
                displayString = "11:00";
                name = "L. Lancaster-Harm";
                score = 660;
            },

            // and so on.....

        );
        order = ASC;
        type = TIMES;
    };
    String = Test;
}

"String = test" is just a test entry and is set in the AppDelegate.m file like this:

if(![[NSUserDefaults standardUserDefaults] objectForKey:@"BlockDepotLeaderboards"]){

 NSMutableDictionary *leadboardHolder = [NSMutableDictionary dictionaryWithObjectsAndKeys:@"Test", @"String", nil];  
 [[NSUserDefaults standardUserDefaults] setObject:leadboardHolder forKey:@"BlockDepotLeaderboards"];
 [[NSUserDefaults standardUserDefaults] synchronize];



}else{
 NSLog(@"Leaderboards Dict Exists %@", [NSUserDefaults standardUserDefaults]);
}

So I know that what I'm after is definitely there. I just know this is going to be something stupid that I'm missing. But I can't see it or figure it out.

Can anyone see what I'm messing up?

A: 

According to the docs:

A default object must be a property list, that is, an instance of (or for collections a combination of instances of): NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary.

Are you sure about all the objects you are trying to serialise? Take a look at NSKeyedArchiver

Also look at this question http://stackoverflow.com/questions/471830/why-nsuserdefaults-failed-to-save-nsmutabledictionary-in-iphone-sdk

lyonanderson
I'm using NSKeyedArchiver elsewhere for something else. This project in primarily a self teaching project so I want to get this nailed. But I was thinking the same thing; As far as I can tell, I'm trying to save an NSDictionary, with two NSStrings and an NSarray which contains 10 NSDictionaries that contain two NSStrings and 1 NSNUmber. But I'll go back and tripple check it.
gargantaun
A: 

As far as I can tell, that's the pertinent code. It's probably "wordier" than it needs to be perhaps. But as I understand it, anything returned from NSUserDefaults will be immutable, so I have to recreate it as a Mutable object, add what needs adding then replace the object in NSUserDefaults.

An easier way is to make a mutableCopy of the immutable dictionary like this:

NSMutableDictionary *newBoards = [[immutableDict mutableCopy] autorelease];
[newBoards setObject:savedData forKey:pTitle];

Also, synchronize is used to force saving the user defaults to disk. It's only influencing what you see when you open the plist in the Finder. From the perspective of the application NSUserDefaults is always up-to-date. Also, the defaults are saved automatically every little while, so the only time you likely ever need to call synchronize is when your application terminates.

Adrian
Small typo: mtuableCopy
Shaggy Frog