0

I have an array that I'm saving to NSUserDefaults, containing an array of my custom class Assignment, which conforms to the NSCoding protocol. The array saves and loads properly, and I can verify that the retrieved first object of the array is of the class Assignment. The problem happens when I try to access ivars of the Assignment object in the array. It crashes and I get the following error:

*** -[CFString respondsToSelector:]: message sent to deallocated instance 0x3948d60

Here is the code I'm using to save to user defaults. Note that I am also retrieving and checking the saved object for debugging purposes.

 -(void)saveToUserDefaults:(NSArray*)myArray
{
    NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];

    if (standardUserDefaults) {
        [standardUserDefaults setObject:[NSKeyedArchiver archivedDataWithRootObject:myArray] forKey:@"Assignments"];
        [standardUserDefaults synchronize];
    }
    NSLog(@"Assignments array saved. (%d assignments in array)",[myArray count]);
    NSData *dataCheck = [[NSData alloc] initWithData:[standardUserDefaults objectForKey:@"Assignments"]];
    NSArray *arrayCheck = [[NSArray alloc] initWithArray:[NSKeyedUnarchiver unarchiveObjectWithData:dataCheck]];
    NSLog(@"Checking saved array (%d assignments in array)",[arrayCheck count]);
    if ([[arrayCheck objectAtIndex:0] isKindOfClass:[Assignment class]]) {
        NSLog(@"It's of the class Assignment.");
    }
    Assignment *testAssignment = [[Assignment alloc] initWithAssignment:[arrayCheck objectAtIndex:0]];
    NSLog(@"Title: %@ Course: %@",[testAssignment title],[testAssignment course]);
}

Everything is fine until I allocate testAssignment, which is where the crash happens. Does anyone have any ideas?

EDIT: Here are my NSCoding methods in the Assignment class:

- (void)encodeWithCoder:(NSCoder *)coder {
    [coder encodeObject:title forKey:@"title"];
    [coder encodeObject:course forKey:@"course"];
    [coder encodeObject:dueDate forKey:@"dueDate"];
    [coder encodeObject:notes forKey:@"notes"];
}

- (id)initWithCoder:(NSCoder *)coder {
    self = [[Assignment alloc] init];
    if (self != nil)
    {
        title = [coder decodeObjectForKey:@"title"];
        course = [coder decodeObjectForKey:@"course"];
        dueDate = [coder decodeObjectForKey:@"dueDate"];
        notes = [coder decodeObjectForKey:@"notes"];
    }   
    return self;
}
Arman
  • 856
  • 2
  • 10
  • 19

1 Answers1

3

Answered my own question. In initWithCoder, I needed to retain all of the objects I was decoding:

//Example    
title = [[coder decodeObjectForKey:@"title"] retain];

Everything works beautifully now. :)

Arman
  • 856
  • 2
  • 10
  • 19
  • 1
    Or if you have properties defined, you can retain it implicitly by using self., i.e. self.title = [coder decodeObjectForKey:@"title"]; – Ben Jakuben Jan 11 '12 at 22:05
  • 1
    This means EVERY OBJECT, apparently, including objects inside initWithCoder: methods. So if the unarchiver is segfaulting on release, go through and make sure your objects inside objects, and objects inside those objects, and the objects inside those objects etc, are all retained upon unarchiving. – Tustin2121 Feb 26 '12 at 05:11