You can save them, they just need to be encoded to NSData first.
You need two methods in the custom objects.
Code:
// Do the same for each thing you want to save.
- (id)initWithCoder:(NSCoder *)aDecoder {
if ((self = [super init])){
[self setSomeProperty:[aDecoder decodeObjectForKey:@"somePropertyName"]];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeObject:someProperty forKey:@"somePropertyName"];
}
You'll then need to loop through your array, encoding each object:
You can save them, they just need to be encoded to NSData first.
You need two methods in the custom objects.
Code:
// Do the same for each thing you want to save.
- (id)initWithCoder:(NSCoder *)aDecoder {
if ((self = [super init])){
[self setSomeProperty:[aDecoder decodeObjectForKey:@"somePropertyName"]];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeObject:someProperty forKey:@"somePropertyName"];
}
You'll then need to loop through your array, encoding each object:
To make this work, you have to add the NSCoding methods encodeWithCoder: and initWithCoder: to your object. Those methods should encode/decode all the instance variables needed to save/reconstruct the object. It's not that hard. Take a look at the methods in NSKeyedArchiver (for encodeWithCoder) and NSKeyedUnarchiver (for initWithCoder).
Check out this password generator app that shows various techniques including using a data container singleton object to share data between objects in your project.
I want to basically add an object to the array in the NSUserDefaults, so looks like I have to load it into filesCopy, change it, and load it back up to NSUserDefaults, right? The NSLog shows that filesCopy contains exactly what I want it to contain. However, it's the last line that's giving the EXC_BAD_ACCESS.
I want to basically add an object to the array in the NSUserDefaults, so looks like I have to load it into filesCopy, change it, and load it back up to NSUserDefaults, right? The NSLog shows that filesCopy contains exactly what I want it to contain. However, it's the last line that's giving the EXC_BAD_ACCESS.
When you save an object into an archive and read it back, you get back an immutable version, even if the object you saved was mutable. The same is true for plists.
The second-to-last line is probably the line that's crashing, since you can't add an object to an NSArray, only an NSMutableArray. Add a line like this:
Check out this password generator app that shows various techniques including using a data container singleton object to share data between objects in your project.
Well, it's definitely the last line that's causing a crash. Archiving "file" doesn't help either. Maybe I should individually archive each object in the array?
Well, it's definitely the last line that's causing a crash. Archiving "file" doesn't help either. Maybe I should individually archive each object in the array?
You can try that, but I doubt it will fix anything.
A bad access error usually means something has been over-released, and you're crashing when you try to reference it.
Try commenting out the line that adds the new object to the array and see if you can write it back to defaults without changing anything.
Take careful note of exactly what source line is causing the crash. Is it crashing in the NSCoding method for your class, by any chance?
You might want to post your NSCoding methods (initWithCoder and encodeWithCoder)
Check out this password generator app that shows various techniques including using a data container singleton object to share data between objects in your project.
It actually looks like it's encoding the objects fine, and yet when I place a breakpoint in the encodeWithCoder method and on the line immediately after [NSKeyedArchiver archivedDataWithRootObject], I press Continue for the first breakpoint, and then it gives me an EXC_BAD_ACCESS before the second breakpoint is even reached.
I'm archiving the NSMutableArray of projects.
Code:
NSMutableArray *projectsCopy = [[NSKeyedUnarchiver unarchiveObjectWithData:[[NSUserDefaults standardUserDefaults] objectForKey:@"projects"]] mutableCopy];
[projectsCopy replaceObjectAtIndex:[[NSUserDefaults standardUserDefaults] integerForKey:@"current project"] withObject:self.currentProject];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:projectsCopy]; //Crashes between encodeWithCoder and the next line here
[[NSUserDefaults standardUserDefaults] setObject:data forKey:@"projects"];
My NSCoder methods are really simple:
Code:
- (id) initWithCoder:(NSCoder *)aDecoder
{
self = [super init];
if (self)
{
[self setTextBox:[aDecoder decodeObjectForKey:@"textBox"]];
//etc. for each property
}
return self;
}
- (void) encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeObject:self.textBox forKey:@"textBox"];
//etc. for each property
}
It actually looks like it's encoding the objects fine, and yet when I place a breakpoint in the encodeWithCoder method and on the line immediately after [NSKeyedArchiver archivedDataWithRootObject], I press Continue for the first breakpoint, and then it gives me an EXC_BAD_ACCESS before the second breakpoint is even reached.
I'm archiving the NSMutableArray of projects.
Code:
NSMutableArray *projectsCopy = [[NSKeyedUnarchiver unarchiveObjectWithData:[[NSUserDefaults standardUserDefaults] objectForKey:@"projects"]] mutableCopy];
[projectsCopy replaceObjectAtIndex:[[NSUserDefaults standardUserDefaults] integerForKey:@"current project"] withObject:self.currentProject];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:projectsCopy]; //Crashes between encodeWithCoder and the next line here
[[NSUserDefaults standardUserDefaults] setObject:data forKey:@"projects"];
My NSCoder methods are really simple:
Code:
- (id) initWithCoder:(NSCoder *)aDecoder
{
self = [super init];
if (self)
{
[self setTextBox:[aDecoder decodeObjectForKey:@"textBox"]];
//etc. for each property
}
return self;
}
- (void) encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeObject:self.textBox forKey:@"textBox"];
//etc. for each property
}
Am I missing anything?
Can you post your entire initWithCoder routine, along with the property declarations for the object's properties?
My bet is that your init routine is setting up some property as auto-released. It's fine until you visit the event loop, and then the property gets deallocated, and your property now points to a dead object.
Have you tried running static analysis on the program? That's worth a try.
Check out this password generator app that shows various techniques including using a data container singleton object to share data between objects in your project.