带有自定义对象数组的Custom对象的NSUserDefaults

时间:2012-06-18 15:07:44

标签: objective-c memory nsmutablearray nsuserdefaults nsdata

我有一个对象,我使用NSKeyedArchiver转换为NSData,然后将其存储到NSUserDefaults中。除了对象具有的数组元素之外,所有内容都被正确保存。数组中的所有对象都符合NSCoder协议(或者他们所谓的任何协议 - 例如self.property = [decoder decodeObjectForKey:@"key"] and [encoder encodeObjectForKey:@"key"]

当我保存对象时,数组的元素仍保留在数组中,但它们的属性本身不会被保存。我打电话给sycnrhonize方法,所以这不是问题。

请注意,所有其他时间我保存&加载它是正确的,它只是不保存属于对象的数组的元素。我必须单独保存吗?

“当前状态”NSNumber未保存。目标和目标正在保存

导入“Level.h”

@implementation Level
@synthesize objective = _objective;
@synthesize isComplete = _isComplete;
@synthesize goldReward = _goldReward;
@synthesize xpReward = _xpReward;
@synthesize missionID = _missionID;
@synthesize currentStatus = _currentStatus;
@synthesize targetName = _targetName;
@synthesize owner = _owner;

-(void)dealloc{

[super dealloc];
  }

-(id)initWithMissionID:(int)number{

if (self = [super init]) {
    self.currentStatus = 0;
    self.isComplete = NO;
    self.missionID = [NSNumber numberWithInt:number];
    [self setUpMisson];
}
return self;
}
-(void)setUpMisson{
if ([self.missionID intValue] == 0) {
    self.xpReward = [NSNumber numberWithInt:100];
    self.goldReward = [NSNumber numberWithInt:100];
    self.objective = [NSNumber numberWithInt:3];
    self.targetName = @"Swordsman";
    CCLOG(@"Gotta kill some swordsmen!");
}
}
-(void)encodeWithCoder:(NSCoder *)encoder{
[encoder encodeObject:self.objective forKey:@"objective"];
[encoder encodeObject:self.isComplete forKey:@"isComplete"];
[encoder encodeObject:self.goldReward forKey:@"goldReward"];
[encoder encodeObject:self.xpReward forKey:@"xpReward"];
[encoder encodeObject:self.missionID forKey:@"missionID"];
[encoder encodeObject:self.currentStatus forKey:@"currentStatus"];
[encoder encodeObject:self.targetName forKey:@"targetName"];
[encoder encodeObject:self.owner forKey:@"owner"];
CCLOG(@"SAVING LEVEL");
}
-(id)initWithCoder:(NSCoder *)decoder{
if (self = [super init]) {
    self.objective = [[decoder decodeObjectForKey:@"objective"]retain];
    self.isComplete = [[decoder decodeObjectForKey:@"isComplete"]retain];
    self.goldReward = [[decoder decodeObjectForKey:@"goldReward"]retain];
    self.xpReward = [[decoder decodeObjectForKey:@"xpReward"]retain];
    self.missionID = [[decoder decodeObjectForKey:@"missionID"]retain];
    self.targetName = [[decoder decodeObjectForKey:@"targetName"]retain];
    self.owner = [[decoder decodeObjectForKey:@"owner"]retain];
    CCLOG(@"LOADING LEVEL");
}
return self;
}
-(void)updateStatusForKill:(AI *)killedTarget{
CCLOG(@"WE KILLED: %@ and OUR GOAL IS: %@",killedTarget.name,self.targetName);

if ([killedTarget.name isEqualToString:self.targetName]) {
    [self setCurrentStatus:[NSNumber numberWithInt:[self.currentStatus intValue]+1]];
    CCLOG(@"Current Status: %i Objective: %i", [self.currentStatus intValue],[self.objective intValue]);
    if ([self.currentStatus intValue] == [self.objective intValue]) {
        [self completeMission];
    }
}
}
-(void)completeMission{
[self.owner setCoins:[NSNumber numberWithInt:[[self.owner coins]intValue] + [self.goldReward intValue]]];
[self.owner setXp:[NSNumber numberWithInt:[[self.owner xp]intValue] + [self.xpReward intValue]]];
CCLOG(@"complete");
[[self.owner missionList]removeObject:self];

}
@end

编辑:“所有者”返回正在保存的对象。我认为这就是问题所在,所以我将其删除并重新测试。

编辑:那没有做任何事!

4 个答案:

答案 0 :(得分:1)

你描述的应该“只是工作”。在自定义对象的encodeWithCoder方法中,您只需编码数组对象,这应该导致数组及其内容被编码。

但是,如果阵列中的任何对象不支持NSCoding,那么将失败。我的猜测是你阵列中的某些东西(或它的子孙子孙)不支持NSCoding。

答案 1 :(得分:1)

我在尝试保存包含属性值和另一个自定义对象的帐户数组时遇到了此问题。我无法使用您提出的解决方案保存我的数据,因为我随意向一个数组添加帐户,并且为动态添加的帐户提供唯一标识符是没有意义的。我最终嵌套了NSCoding协议:

在我的AccountManager课程中:

- (void) saveAllAccounts {
    [self deleteAllAccounts]; //Just removes whatever was previously stored there
    [[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:accountArray] forKey:saveAccountsArrayKey];
    [[NSUserDefaults standardUserDefaults] synchronize];
}

在我的Account课程中:

- (void) encodeWithCoder:(NSCoder *)aCoder {
    [aCoder encodeObject:username forKey:@"username"];
    [aCoder encodeObject:token forKey:@"token"];
    [aCoder encodeObject:specialID forKey:@"special ID"];
    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:deviceArray];
    [[NSUserDefaults standardUserDefaults] setObject:data forKey:@"device array"];
}

- (id) initWithCoder:(NSCoder *)aDecoder {
    self = [super init];
    if (self != nil) {
        username = [[aDecoder decodeObjectForKey:@"username"] retain];
        token = [[aDecoder decodeObjectForKey:@"token"] retain];
        ecoID = [[aDecoder decodeObjectForKey:@"eco ID"] retain];
        NSData *deviceArrayData = [[NSUserDefaults standardUserDefaults] objectForKey:@"device array"];
        if (deviceArrayData != nil) {
            NSArray *savedArray = [NSKeyedUnarchiver unarchiveObjectWithData: deviceArrayData];
            if (savedArray != nil)
                deviceArray = [[NSMutableArray alloc] initWithArray:savedArray];
        }   
    }
    return self;
}

在我的AccountDevice课程中:

- (void) encodeWithCoder:(NSCoder *)aCoder {
    [aCoder encodeObject:pairingPassword forKey:@"pairing password"];
    [aCoder encodeObject:devicePin forKey:@"device pin"];
}

- (id) initWithCoder:(NSCoder *)aDecoder {
    self = [super init];
    if (self != nil) {
        password = [[aDecoder decodeObjectForKey:@"password"] retain];
        pin = [[aDecoder decodeObjectForKey:@"pin"] retain];        
    }
    return self;
}  

这可能是一个小小的车,因为我还没有完成测试,但我的初步测试是成功的,我认为这个概念就在那里。

答案 2 :(得分:0)

即使是非对象的值,您似乎也在使用-encodeObject:forKey:-decodeObjectForKey:。例如,在您的-initWithMissionID:中,您有:

self.isComplete = NO;

这让我觉得complete属于BOOL属性,但您的-encodeObject:forKey:说:

[encoder encodeObject:self.isComplete forKey:@"isComplete"];

我想你可能想要拨打-encodeBool:forKey:,就像这样:

[encoder encodeBool:self.isComplete forKey:@"isComplete"];

另一方面,如果问题那么简单,我真的期待某种警告。你有任何警告吗?推断其他属性的类型更难,但要查看每个属性是否存在同类问题。

答案 3 :(得分:0)

为每个任务找到了使用Unique-Id系统的解决方法,并将每个任务的进度分别保存到NSUserDefaults中,然后再次加载。不理想,但它的工作原理。谢谢大家的帮助!