views:

773

answers:

3

I have the following two archiving methods:

    - (void) encodeWithCoder: (NSCoder *) encoder {
    [encoder encodeObject:self.exercises forKey:@"exercises"];
    [encoder encodeObject:self.title forKey:@"title"];
    [encoder encodeObject:self.description forKey:@"description"];
    [encoder encodeInteger:self.idnum forKey:@"idnum"];
    [encoder encodeInteger:self.rating forKey:@"rating"];
    [encoder encodeInteger:self.frequency forKey:@"frequency"];
    NSLog(@"Encoding!");

}

- (id) initWithCoder: (NSCoder *) decoder {
    self.exercises =   [[decoder decodeObjectForKey:@"exercises"] retain];
    self.title =       [[decoder decodeObjectForKey:@"title"] retain];
    self.description = [[decoder decodeObjectForKey:@"description"] retain];
    self.idnum =       [[decoder decodeIntegerForKey:@"idnum"] retain];
    self.rating =      [[decoder decodeIntegerForKey:@"rating"] retain];
    self.frequency =   [[decoder decodeIntegerForKey:@"frequency"] retain];
    NSLog(@"Decoding!");
    return self;
}

And a header:

    @interface Workout : NSObject{

    NSMutableArray *exercises; 
    NSString *title;
    NSString *description;
    NSInteger idnum;
    NSInteger rating;
    NSInteger frequency;
}

- (void) encodeWithCoder: (NSCoder *) encoder;
- (id) initWithCoder: (NSCoder *) decoder;

@property(nonatomic,retain) NSMutableArray *exercises; 
@property(nonatomic,retain) NSString *title;
@property(nonatomic,retain) NSString *description;
@property(nonatomic) NSInteger idnum;
@property(nonatomic) NSInteger rating;
@property(nonatomic) NSInteger frequency;
@end

It seems simple enough. encodeInteger takes an NSInteger, which I pass to it, and decodeIntegerForKey returns an NSInteger, but I get this weird errors:

warning: invalid receiver type 'NSInteger'

and when the decodeIntegerForKey instruction is executed, I get an exec bad access.

Why is this happening?

+1  A: 

Is your project's deployment target set to Mac OS 10.5 or later? NSInteger was only introduced in Leopard so if you're targeting Tiger you will need to provide implementations of NSInteger and -decode/encodeIntegerForKey:

As an aside, generally you should avoid using accessors when setting ivars in init methods. You should normally just set the ivars directly.

Rob Keniger
A: 

Thank you for your help. The problem was that I was retaining an integer, which returns a pointer.

kodai
Retaining an integer doesn't return anything. You can't send a `retain` message to an integer (without getting at least a warning), nor pass an integer to `CFRetain` (without getting a warning), and you will almost certainly crash if you try either one. This, of course, matches the results you described: You got a warning, and crashed. You can only retain an Objective-C or Core Foundation object, and integers aren't Obj-C/CF objects.
Peter Hosey
+4  A: 

There are a couple problems with the posted code. First:

self.idnum =       [[decoder decodeIntegerForKey:@"idnum"] retain];

That code is sending 'retain' to an NSInteger. NSIntegers aren't objects though, they're just scalars. That is illegal. Just use this instead:

self.idnum =       [decoder decodeIntegerForKey:@"idnum"];

Next, this code:

self.exercises =   [[decoder decodeObjectForKey:@"exercises"] retain];

Is over retaining, and will cause a leak. Since you declared exercises like:

@property(nonatomic,retain) NSMutableArray *exercises; 

That "retain" means that when you call the setter, it will retain the passed in value before sticking it in the "exercises" instance variable. You're retaining before calling the setter though, so that's a double retain.

You could fix this by changing your code to either:

exercises =   [[decoder decodeObjectForKey:@"exercises"] retain];

Or:

self.exercises =   [decoder decodeObjectForKey:@"exercises"];
Jon Hess