EDIT: Here is a working version. I was able to retrieve my object within the NSMUtableArray after I saved and loaded it from the NSUserDefaults via NSCoding. I think it's important to mention, that you not only need to de-archive the array, but also all its content. As you can see, I had to not only store the NSData of my freeze object, but also the NSData of my array:
// My class "Freeze"
@interface Freeze : NSObject <NSCoding> // The NSCoding-protocoll is important!!
{
NSMutableString *name;
}
@property(nonatomic, copy) NSMutableString *name;
-(void) InitString;
@end
@implementation Freeze
@synthesize name;
-(void) InitString {
name = [[NSMutableString stringWithString:@"Some sentence... lalala"] retain];
}
// Method from NSCoding-protocol
- (void)encodeWithCoder:(NSCoder *)encoder
{
//Encode properties, other class variables, etc
[encoder encodeObject:self.name forKey:@"name"];
}
// Method from NSCoding-protocol
- (id)initWithCoder:(NSCoder *)decoder
{
self = [super init];
if( self != nil )
{
//decode properties, other class vars
self.name = [decoder decodeObjectForKey:@"name"];
}
return self;
}
@end
Freeze *freeze;
NSMutableArray *runes;
NSMutableArray *newRunes;
runes = [[NSMutableArray alloc] init];
newRunes = [[NSMutableArray alloc] init];
freeze = [[Freeze alloc] init];
[freeze InitString];
[runes addObject:freeze];
[self saveState];
[self restoreState];
Freeze *newFreeze = [[Freeze alloc] init];
newFreeze = [newRunes objectAtIndex:0];
NSString *String = [NSString stringWithString:newFreeze.name];
NSLog(@"%@", String);
//-----------------------------------------------------------------------------
- (void) saveState
{
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
NSData* myClassData = [NSKeyedArchiver archivedDataWithRootObject:freeze];
[defaults setObject:myClassData forKey:@"MyClass"];
NSData* myClassArrayData = [NSKeyedArchiver archivedDataWithRootObject:runes];
[defaults setObject:myClassArrayData forKey:@"MyClassArray"];
}
- (void) restoreState
{
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
NSData* myClassData = [defaults objectForKey:@"MyClass"];
freeze = [NSKeyedUnarchiver unarchiveObjectWithData:myClassData];
NSData* myClassArrayData = [defaults objectForKey:@"MyClassArray"];
NSArray *savedMyClassArray = [NSKeyedUnarchiver unarchiveObjectWithData:myClassArrayData];
if( savedMyClassArray != nil )
newRunes = [[NSMutableArray alloc] initWithArray:savedMyClassArray];
else
newRunes = [[NSMutableArray alloc] init];
}
EDIT: This is an error I got before, it doesn't show up anymore with the updated version above.
It crashes at the very end and the debugger reveals the following error: ** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSConcreteMutableData InitString]: unrecognized selector sent to instance 0x6b1fe20'*
Furthermore, it says that "NewFreeze" is not of type CFString. Does anybody have a clue what's going on? I really want to save my Objects like that.
You certainly can save your own objects using the
NSKeyedArchiver
class like you want to. But:And like it was mentioned before, you can't save it to NSUserDefaults. You can save it to a file in the application documents directory, though.
EDIT: here is some code that I wrote about a year ago as a test. I think this might be very close to what your trying to do. There's some stuff there that is not related, like loading a plist from the main bundle, but I'll leave it in just in case someone might find it useful.
HighScoresManager.h
HighScoresManager.m
Maybe I should have just uploaded the files somewhere and linked them here... anyway, it's done now.
The problem is that storing custom classes as a node in the Settings plist (NSUserDefaults) is not allowed, since the data is stored in the file system rather than an object from the application. The settings app (where this data will also be visible) has no idea what a "Freeze" object is. The best way to handle what you want to do is to probably use Core Data.
also of note: the error you are getting is caused at the end of the method when you try to initalize a new
Freeze
object from yourrunes
array, because when you put the object into the runes array you encapsulated it as aNSData
object first, but when you get it out you don't dearchive it before setting it toNewFreeze