【问题标题】:My NSMutableArray suddenly becomes a CALayer我的 NSMutableArray 突然变成了 CALayer
【发布时间】:2012-04-29 21:06:38
【问题描述】:

我觉得我产生了幻觉。我正在尝试为我的 Concentration-lke 游戏添加一些持久性。我想跟踪高分。我今天让这个部分工作了一段时间,现在它已经全部消失了(我认为这是正确的 iOS 术语)。现在,我的 allHighScores NSMutablearray 突然变成了一个 CALayer。我正在使用 NSKeyed 归档。在 allHighScores 加载数据之前,我的文件中有一个断点。在单步执行应用程序时,allHighScores 作为 NSMutableArray 存在 - 然后,在下一步,它突然变成了 CA 层。嗯?

-(id)init 
{
    self = [super init];
    if (self) {
        NSString *path = [self flipScoreArchivePath];
        NSLog(@"Path is %@", path);
        allHighScores = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
        if (!allHighScores)  {
        allHighScores = [[NSMutableArray alloc] init];
        }
    }
    return self;
}


+(FlipHighScoreStore *)sharedStore {
    static FlipHighScoreStore *sharedStore = nil;
    if (!sharedStore) {
        sharedStore = [[super allocWithZone:nil]init];
    }
    return sharedStore;
}

不知何故,调用 NSKeyedUnarchiver 将我的 allHighScores 从 NSMutableArray 更改为 CALayer。我很困惑。

我尝试在取消归档指令中添加保留,但这没有帮助。

这是我的编码/解码代码:

-(void)encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeObject:self.themeChosen forKey:@"themeChosen"];
[aCoder encodeInt:self.highScore forKey:@"highScore"];
[aCoder encodeInt:self.scoreStartLevel forKey:@"scoreStartLevel"];
[aCoder encodeInt:self.scoreFinishLevel forKey:@"scoreFinishLevel"];
[aCoder encodeObject:scoreDateCreated forKey:@"scoreDateCreated"];}

-(id)initWithCoder:(NSCoder *)aDecoder {
if (self) {
    self.themeChosen = [aDecoder decodeObjectForKey:@"themeChosen"];
    self.highScore = [aDecoder decodeIntForKey:@"highScore"];
    self.scoreStartLevel = [aDecoder decodeIntForKey:@"scoreStartLevel"];
    self.scoreFinishLevel = [aDecoder decodeIntForKey:@"scoreFinishLevel"];
    scoreDateCreated = [aDecoder decodeObjectForKey:@"scoreDateCreated"];
}
return self;}

更新:当“highscores.archive”文件已经存在并且再次调用保存时程序崩溃。我可以启动应用程序,查看高分 - 他们在那里并愉快地检索,但保存代码:

-(BOOL)saveHighScores {
NSString *path = [self flipScoreArchivePath];
return [NSKeyedArchiver archiveRootObject:allHighScores toFile:path];}

导致 EXC_BAD_ACCESS。路径是正确的,所以不知何故 allHighScores 不是。

【问题讨论】:

  • 您能告诉我们您是如何在FlipHighScore 中实现NSCoding 协议的吗?或者任何类名?
  • 试试这个NSLog(@"unarchived class %@",NSStringFromClass([allHighScores class])); 并记下输出。
  • 当一个对象神奇地转变为另一个对象时,这表明第一个对象被过度释放(或保留不足)并被释放,另一个对象被分配到它的位置。
  • 是的,我正在使用 ARC。 - 我将添加一点编码!我在 allHighScores 未存档之前和之后登录 - 在我得到“unarchived class null”之前和在我得到“unarchived class CA Layer”之后。
  • 为什么在+ sharedStore 中使用[super alloc] 而不是[self alloc]

标签: ios nskeyedarchiver


【解决方案1】:

这里的问题是您没有保留取消归档的结果。根据Basic Memory Management Rules,名称为+unarchiveObjectWithFile: 的方法将返回一个自动释放的对象。因此,由于您将其放入 ivar,因此您需要保留此对象,否则它将从您的下方被释放。

尽管在您的情况下,由于您想要一个 可变 数组,您实际上需要调用 -mutableCopy,因为 NSKeyedUnarchive 只会给您一个不可变数组。

-(id)init {
    if ((self = [super init])) {
        NSString *path = [self flipScoreArchivePath];
        NSLog(@"Path is %@", path);
        allHighScores = [[NSKeyedUnarchiver unarchiveObjectWithFile:path] mutableCopy];
        if (!allHighScores) {
            allHighScores = [[NSMutableArray alloc] init];
        }
    }
    return self;
}

您的 -initWithCoder: 没有调用 super。你需要说

if ((self = [super initWithCoder:aDecoder])) {

【讨论】:

  • 谢谢!我添加了保留,行为没有改变。我认为我不需要保留,因为我使用的是 ARC。
  • @AugustusS-R:啊,我不知道你在使用 ARC。如果你想要一个可变数组,你仍然需要-mutableCopy
  • 谢谢你的想法,凯文! allHighScores 仍然成为 CALayer(这显然是一件坏事......)
  • @AugustusS-R 如果您添加了retain 并且没有收到错误,则说明您没有使用 ARC。如果启用了 ARC,编译器将拒绝任何发送retain 的正常尝试。
  • @KevinBallard 你没有返回self(我显然因为那个错误而被否决了)而且你还没有提供一个机制让他实际上retain他的NSMutableArray。
【解决方案2】:

你试过了吗?

-(id)init { 
    if ((self = [super init])) {
        NSString *path = [self flipScoreArchivePath];
        NSLog(@"Path is %@", path);
        allHighScores = [[NSKeyedUnarchiver unarchiveObjectWithFile:path] mutableCopy];
        if (!allHighScores) {
            allHighScores = [[NSMutableArray alloc] init];
        }
        // All-important new line....
        [self setAllHighScores:allHighScores];
    }
    return self;
}

编辑/更新: 所以,这是我在上面示例中实际意图的两个版本(我在这里假设他的 ivar allHighScores 具有相应的属性):

-(id)init { 
    if ((self = [super init])) {
        NSString *path = [self flipScoreArchivePath];
        NSLog(@"Path is %@", path);
        self.allHighScores = [[NSKeyedUnarchiver unarchiveObjectWithFile:path] mutableCopy];
        if (!self.allHighScores) {
            self.allHighScores = [[NSMutableArray alloc] init];
        }
    }
    return self;
}

这是我实际做的方式:

-(id)init { 
    if ((self = [super init])) {
        NSMutableArray *arr = [[NSKeyedUnarchiver unarchiveObjectWithFile:[self flipScoreArchivePath]] mutableCopy];
        if (!arr) arr = [[NSMutableArray alloc] init];
        [self setAllHighScores:arr];
    }
    return self;
}

【讨论】:

  • 最好的货运狂热节目。分配给一个ivar,然后调用同一个setter?这没有任何意义。
  • 返回自我;也不见了。
  • 除非,当然,因为他使用 ARC,所以对象不会通过简单地分配给 ivar 来保留。他有一个奇怪的问题。我想确保我们检查了所有基础知识。感谢所有反对诚实的帮助尝试的人!!!你对自己感觉更好吗?
  • @KevinBallard 所以,当我犯了一个错误时(因为我从未直接分配给 ivars,我读了一个不存在的声明),这是货物崇拜编程,但是当你错过 @987654325 @,这只是一个“哎呀”?对我来说听起来像是双重标准。也许你可以更慈善一点,直到你知道有人不知道他们在讨论什么。
  • @mbm30075:你的“错误”是将随机的代码块放在一起,希望它能起作用,而没有更深入地了解正在发生的事情。这几乎是货物崇拜编程的字典定义。
猜你喜欢
  • 2016-01-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-16
  • 1970-01-01
  • 2019-02-22
  • 1970-01-01
相关资源
最近更新 更多