开发者

NSUserDefaults, NSCoder, Custom Class - iPhone app question

I'm having an error and I guess I'm doing something wrong in the following process. Firstly, I have a class Contacts:

@interface Contact : NSObject<NSCoding> {
    @private
    ABRecordRef ref;
    NSString *first;
    NSString *last;
    bool selected;
    NSString *phoneNumber;
}

And in Contact's implementation, I have:

- (void)encodeWithCoder:(NSCoder *)encoder {
    [encoder encodeObject:first forKey:@"First"];
    [encoder encodeObject:last forKey:@"Last"];
    [encoder encodeObject:[NSNumber numberWithInteger: ABRecordGetRecordID(ref)] forKey:@"Ref"  ];
    [encoder encodeObject:first forKey:@"PhoneNumber"];
}

- (id)initWithCoder:(NSCoder *)decoder {
    self = [[Contact alloc] init];
    first = [decoder decodeObjectForKey:@"First"];
    last = [decoder decodeObjectForKey:@"Last"];
    ABAddressBookRef addressBook = ABAddressBookCreate();
    NSNumber *num = [decoder decodeObjectForKey:@"Ref"];
    ref = ABAddressBookGetPersonWithRecordID(addressBook,(ABRecordID)num);
    phoneNumber = [decoder decodeObjectForKey:@"PhoneNumber"];

    return self;
}

And when I create what I call a "group" in my app, I do the following:

+ (void)addGroupWithName:(NSString *)s contacts:(NSMutableArray *)arr {
    NSLog(@"added group name with name %@",s);
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:arr];
    [defaults setObject:data forKey:s];
    [defaults synchronize];
    //[UserData setDefaultWithName:s object:arr];
}

which, according to some print statements I make, seems to work fine.

Then, when the app launches, I try to print those objects I stored:

+ (void)printGroups {
    NSMutableArray *arr = [UserData getGroupNames];
    NSLog(@"group names are %@",arr);
    for(int i = 0; i < [arr count]; i++) {
        NSString *name = [arr objectAtIndex:i];
        NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
        NSData *data = [defaults objectForKey:name];
        NSArray *a = [NSKeyedUnarchiver unarchiveObjectWithData:data];
        NSLog(@"name = %@",name);
        NSLog(@"array count is %i",[a count]);
        for(int i = 0; i < [a count]; i++) {
            NSLog(@"on index %i",i);
            Contact *c = [a objectAtIndex:i];
            NSLog(@"got contact开发者_运维知识库");
            if(c == nil)
                NSLog(@"it's nil!");    

            NSLog(@"class is %@", NSStringFromClass([c class]));
            NSLog(@"got contact %@",c);
        }
        NSLog(@"array = %@",a);
    }
}

However, on the line NSLog(@"got contact %@",c);, my program stops running. It prints everything fine, and even prints that the object's class is "Contact". But then it stops. It looks like maybe there is an error but on the left hand side I just see question marks under the "By Thread" option in XCode 4 in the error area on the left.

So what am I doing wrong?

NSUserDefaults, NSCoder, Custom Class - iPhone app question


First, your init should look like this:

- (id)initWithCoder:(NSCoder *)decoder 
{
    if(self = [super init])
    {
        first = [[decoder decodeObjectForKey:@"First"] retain];
        last = [[decoder decodeObjectForKey:@"Last"] retain];
        ABAddressBookRef addressBook = ABAddressBookCreate();
        NSNumber *num = [decoder decodeObjectForKey:@"Ref"];
        ref = ABAddressBookGetPersonWithRecordID(addressBook,(ABRecordID)num);
        phoneNumber = [[decoder decodeObjectForKey:@"PhoneNumber"] retain];
    }

    return self;
}

In encodeWithCoder you encode first twice, you probably wanted phoneNumber in the second one.

Maybe I'm missing where you're creating new Contact objects, but you will probably want a standard init method to create the contact initially (initWithCoder only initializes when you're decoding from data or a file, I believe). This would probably want to look something like:

- (id)initWithFirst:(NSString *)firstIn last:(NSString *)lastIn phone:(NSString *)phoneIn 
{
    if(self = [super init])
    {
        first = [firstIn retain];
        last = [lastIn retain]; 
        phoneNumber = [phoneIn retain];
        selected = NO;
        ref = //however you generate a record reference
    }

    return self;
}

I'm not sure if anything else is wrong, but try changing these two things and see if it makes a difference. Make sure you have a dealloc where you release all of your class members.


Hm. Turned out if I added a retain on the decode method, everything worked. I mean, retain all the objects.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜