Reputation: 1179
I try to add a custom object class i created to nsuserdefaults array but it always stays empty. The log i'm getting is:
"Note that dictionaries and arrays in property lists must also contain only property values"
my code is:
-(void)addProgramWithName:(NSString *)nameOfProgram andWithArrayOfIntervals:(NSMutableArray *)arrayOfIntervals{
Program *tempProgram = [[Program alloc] init];
tempProgram.nameOfProgram = nameOfProgram;
tempProgram.arrayOfIntervals = arrayOfIntervals;
NSMutableArray *tempArrayOfPrograms = [NSMutableArray arrayWithArray: [[NSUserDefaults standardUserDefaults] arrayForKey: @"arrayOfPrograms"]];
[tempArrayOfPrograms addObject:tempProgram];
[defaults setObject:tempArrayOfPrograms forKey:@"arrayOfPrograms"];
[defaults synchronize];
}
What may the reason be?
Upvotes: 0
Views: 109
Reputation: 18253
The reason for the problem is what the log message says - that for a property list, any object you add to the array (or dictionary) must be a property value (strings, numbers, dates and arrays/dictionaries thereof).
So in your case it seems that you have read in values from the user defaults, and now you want to add some custom objects to the values you have read in.
If you don't intend to write the amended array back out to the user defaults, there is nothing wrong with this approach (although it strikes me as a somewhat gung-ho approach to data structures).
On the other hand, if you need to write the data back, you should only store property values in the array. For more complex objects, that can be accomplished by encoding it in a dictionary object with keys and values.
Depending on your needs, Core Data might be more suited for your data, though.
Upvotes: 1
Reputation: 18561
When you store an array or dictionary into NSUserDefaults it gets condensed into a plist on disk. This means your custom object needs to be converted into a format that can be stored in a plist. There are lots of ways to do this depending on the type of data your object holds but this method will work with pretty much any custom object and should be pretty robust.
Thanks to Apple's well designed frameworks, its pretty simple to achieve :)
In your Program.h
add the <NSCoding>
protocol.
@interface Program : NSObject <NSCoding>
Then in your Program.m
make sure you implement the following methods.
#pragma mark - NSCoding
-(void)encodeWithCoder:(NSCoder *)encoder
{
// For each of the Program's properties that needs to be stored.
[encoder encodeObject:self.property forKey:@"PropertyKey"];
}
-(id)initWithCoder:(NSCoder *)decoder
{
if (self=[super init]) {
self.property = [decoder decodeObjectForKey:@"PropertyKey"];
}
return self;
}
This protocol and its methods allow your custom object for be encoded and decoded on the fly. This is important so we can get your objects into the right format.
Next we are going to archive your array before storing it. So replace your code with this:
// Old Line
// [defaults setObject:tempArrayOfPrograms forKey:@"arrayOfPrograms"];
// New Lines
id archivedObject = [NSKeyedArchiver archivedDataWithRootObject:tempArrayOfPrograms];
[defaults setObject:archivedObject forKey:@"arrayOfPrograms"];
Now the final step is to make sure you're unarchiving on the way out. So anywhere you load the array from NSUserDefaults
make sure you unarchive it.
// Get the archived array.
id archivedObject = [[NSUserDefaults standardUserDefaults] objectForKey:@"arrayOfPrograms"];
// Unarchive the array.
NSArray *unarchivedArray = [NSKeyedUnarchiver unarchiveObjectWithData:archivedObject];
// Its already a mutable array if you put a mutable array in but just to be safe.
NSMutableArray *arrayFromDefaults = [NSMutableArray arrayWithArray:unarchivedArray];
Upvotes: 0