PDA

View Full Version : NSUserDefaults problems




Soulstorm
Nov 22, 2007, 08:50 AM
I have two classes that look like this:

@interface ModStatus: NSObject <NSCoding>{

NSMutableDictionary *properties;
}

- (void)setProperties:(NSDictionary *)otherProperties;
- (NSMutableDictionary *)properties;

@end
@implementation ModStatus

#pragma mark Inits, setters, getters

- (id) init
{
self = [super init];
if (self != nil) {
NSArray *values = [NSArray arrayWithObjects:@"modName", @"modLocation", @"preferenceFileLocation", @"isFirstTime",nil];
NSArray *keys = [NSArray arrayWithObjects:@"<not set>", @"<mod location not set>", @"<not set>", [NSNumber numberWithBool:YES], nil];
properties = [NSMutableDictionary dictionaryWithObjects:values forKeys:keys];
}
return self;
}

- (void)setProperties:(NSDictionary *)otherProperties
{
[properties setDictionary:otherProperties];
}

- (NSMutableDictionary *)properties
{
return properties;
}

#pragma mark NSCoding
- (void)encodeWithCoder:(NSCoder *)coder
{
//[coder encodeObject:properties forKey:@"properties"];
}

- (id)initWithCoder: (NSCoder *) coder
{
//properties = [coder decodeObjectForKey:@"properties"];
return self;
}

#pragma mark dealloc
- (void) dealloc
{
[properties release];
[super dealloc];
}

@end





@interface ModSelector : NSObject <NSCoding>{
NSMutableArray *modStatuses;
int SELECTED_MOD;
}
- (id) initWithStatuses :(NSArray *)statuses;
- (void)changeSelectedMod:(int)newSelection;
- (void)setModStatuses:(NSArray *)newModStatuses;
- (ModStatus *)currentModStatus;
- (ModStatus *)modStatusAtIndex:(unsigned)index;
- (NSMutableArray *)modStatuses;
- (unsigned)count;

- (void)selectModWithName:(NSString *)name;
- (id)valueForCurrentModKey: (id)key;
@end


@implementation ModSelector
- (id) init
{
self = [super init];
if (self != nil) {
ModStatus *status1 = [[[ModStatus alloc]init]autorelease];
ModStatus *status2 = [[[ModStatus alloc]init]autorelease];
[[status1 properties]setValue:@"FS2_Open" forKey:@"modName"];
[[status2 properties]setValue:@"BBTRL" forKey:@"modName"];

modStatuses = [[NSMutableArray alloc]init];

[modStatuses addObject:status1];
[modStatuses addObject:status2];

SELECTED_MOD = FIRST_MOD;
}
return self;
}

- (id) initWithStatuses :(NSArray *)statuses
{
self = [super init];
if (self != nil) {
modStatuses = [[NSMutableArray alloc]init];
[modStatuses setArray:statuses];
}
return self;
}

- (void)setModStatuses:(NSArray *)newModStatuses
{
[modStatuses setArray:newModStatuses];
}

- (ModStatus *)currentModStatus
{
return [modStatuses objectAtIndex:SELECTED_MOD];
}

-(void)selectModWithName:(NSString *)name
{
int i;
for (i=0; i<[modStatuses count]; i++) {
//NSLog(@"ASD");
if ([name isEqualToString:[[[modStatuses objectAtIndex:i]properties]valueForKey:@"modName"]] == TRUE){
SELECTED_MOD = i;
break;
}
}
}

- (NSMutableArray *)modStatuses
{
return modStatuses;
}

- (ModStatus *)modStatusAtIndex:(unsigned)index
{
if ([self count] > index)
return [modStatuses objectAtIndex:index];
return nil;
}

- (void)changeSelectedMod:(int)newSelection
{
SELECTED_MOD = newSelection;
}

#pragma mark Getting mod parameters

- (id)valueForCurrentModKey: (id)key
{
ModStatus *currentObject = [modStatuses objectAtIndex:SELECTED_MOD];
return [[currentObject properties]valueForKey:key];
}

- (unsigned)count
{
return [modStatuses count];
}

#pragma mark NSCoding

- (void)encodeWithCoder:(NSCoder *)coder
{
[coder encodeObject:modStatuses forKey:@"modStatuses"];
}

- (id)initWithCoder: (NSCoder *) coder
{
modStatuses = [coder decodeObjectForKey:@"modStatuses"];
return self;
}

#pragma mark dealloc
- (void) dealloc
{
[modStatuses release];
[super dealloc];
}



I build a Cocoa Application, and inside the -init function of one of the classes, I have the following lines of code:

NSMutableDictionary *prop = [NSMutableDictionary dictionary];
prefs = [NSUserDefaults standardUserDefaults];
ModSelector *ms = [[ModSelector alloc]init];
[prop setObject:ms forKey:@"modSelector"];
[prefs registerDefaults:prop];


The application crashes and the debugger comes up at "[prefs registerDefaults:prop]" without telling me why. Can anyone help me with this?



kainjow
Nov 22, 2007, 08:57 AM
From the docs:

A defaultís value can be only property list objects: NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary.

If you want to use your ModSelector object as a value in the user defaults, I'd suggest archiving it (using NSArchiver or NSKeyedArchiver).

Soulstorm
Nov 24, 2007, 03:21 AM
If you want to use your ModSelector object as a value in the user defaults, I'd suggest archiving it (using NSArchiver or NSKeyedArchiver).

I tried that, and my application crashes at startup. here is the code:


@implementation GeneralHandler

- (id) init
{
self = [super init];
if (self != nil) {

NSMutableDictionary *prop = [NSMutableDictionary dictionary];

prefs = [NSUserDefaults standardUserDefaults];
ModSelector *ms = [[ModSelector alloc]init];
NSData *ModSelectorData = [NSKeyedArchiver archivedDataWithRootObject:ms];
[prop setObject:ModSelectorData forKey:@"ModSelectorData"];
[prop setObject:@"hello world" forKey:@"hello"];
[prefs registerDefaults:prop];

//loading...
ModSelector *sel = [NSKeyedUnarchiver unarchiveObjectWithData:[prefs objectForKey:@"ModSelectorData"]];

}
return self;
}


................ other code................
@end


return error:
[Session started at 2007-11-24 11:13:18 +0200.]
multiplemodsupport 2(1516) malloc: *** error for object 0x156cf0: incorrect checksum for freed object - object was probably modified after being freed.
*** set a breakpoint in malloc_error_break to debug

Tried to locate the line that raises the error, and it is the line that unarchives the object from the preferences. Also, some lined like those:

NSData *writableData = [NSKeyedArchiver archivedDataWithRootObject:availableModSelector];
[prefs setObject:writableData forKey:@"ModSelectorData"]; will also raise an exception, but the debugger won't tell me why this time. I don't know how to fix it. Anyone with a good idea? Does this have something to do with my encoding and decoding methods?

kainjow
Nov 24, 2007, 10:11 AM
Sounds like a memory management problem with your encodeWithCoder: method.

Also be sure to release your ms object after adding it to the dictionary. You are leaking memory at this point (assuming you don't have GC enabled).