Cocos2d iphone 使用NSKEYEDUNACHIVER加载保存状态时执行错误访问

Cocos2d iphone 使用NSKEYEDUNACHIVER加载保存状态时执行错误访问,cocos2d-iphone,nsuserdefaults,exc-bad-access,nskeyedunarchiver,Cocos2d Iphone,Nsuserdefaults,Exc Bad Access,Nskeyedunarchiver,我对一个CCSprite进行了子类化,以生成一个可以编码和解码的对象。我想保存精灵状态并在特定位置再次加载。除了使用NSKeyedUnarchiver进行解码(请参见下面的LoadiconScriteState)之外,一切似乎都很正常,它提供了EXC\u BAD\u访问权限下面是代码: HelloWorldLayer.h @interface CCIconSprite : CCSprite { NSString *iconName; float iconXPos; float

我对一个
CCSprite
进行了子类化,以生成一个可以编码和解码的对象。我想保存精灵状态并在特定位置再次加载。除了使用
NSKeyedUnarchiver
进行解码(请参见下面的
LoadiconScriteState
)之外,一切似乎都很正常,它提供了
EXC\u BAD\u访问权限
下面是代码:

HelloWorldLayer.h

@interface CCIconSprite : CCSprite {
   NSString *iconName;
   float iconXPos;
   float iconYPos;
}

@property (nonatomic, retain) NSString *iconName;
@property (nonatomic, assign) float iconXPos;
@property (nonatomic, assign) float iconYPos;

+ (id)iconWithType:(NSString*)imageName;
- (id)initWithIconType:(NSString*)imageName;
@end

@interface HelloWorldLayer : CCLayer < NSCoding>
{
    CCIconSprite* testSprite;
    BOOL savedState;
    CGSize size;
    CCMoveTo* moveTo;
    NSMutableArray* saveSpriteArray;
    NSData* savedSpriteData;

}
+(CCScene *) scene;

@end
编码和解码:

- (id)initWithCoder:(NSCoder *)decoder {
   NSString* imageFileName = [decoder decodeObjectForKey:@"imageFileName"];
   self = [self initWithIconType:imageFileName];
   if (!self) return nil;

   self.iconXPos = [decoder decodeFloatForKey:@"iconXPos"];
   self.iconYPos = [decoder decodeFloatForKey:@"iconYPos"];

   return self;
}

- (void)encodeWithCoder:(NSCoder *)encoder
{
   [encoder encodeObject:iconName forKey:@"imageFileName"];
   [encoder encodeFloat:self.iconXPos forKey:@"iconXPos"];
   [encoder encodeFloat:self.iconYPos forKey:@"iconYPos"];
}

@end
HelloWorldLayer实现:

@implementation CCIconSprite
@synthesize  iconXPos;
@synthesize iconYPos;
@synthesize iconName;

+ (id)iconWithType:(NSString*)imageName
{
    return [[[[self class] alloc] initWithIconType:imageName] autorelease];
}

- (id)initWithIconType:(NSString*)imageName
{
   self = [super initWithFile:imageName];
   if (!self) return nil;

   iconName = imageName;

   self.position = ccp(iconXPos, iconYPos);

   return self;
}
@implementation HelloWorldLayer
+(CCScene *) scene
{
CCScene *scene = [CCScene node];
HelloWorldLayer *layer = [HelloWorldLayer node];
[scene addChild: layer];
    return scene;
}

-(id) init
{
if( (self=[super init]) ) {
    self.scale = 0.5;
    savedState = NO;

    size = [[CCDirector sharedDirector] winSize];

    testSprite = [CCIconSprite spriteWithFile:@"Icon.png"];
    testSprite.position = ccp(size.width/4, size.width/4);
    testSprite.anchorPoint = ccp(0,0);
    [self addChild:testSprite];

    moveTo = [CCMoveTo actionWithDuration:3 position:ccp(3*size.width/4, 3*size.width/4)];
    [testSprite runAction:moveTo];

    [self schedule:@selector(saveAndLoadSpriteState)];

}
return self;
}
保存和加载状态:

-(void)saveIconSpriteState  {
    saveSpriteArray = [[NSMutableArray alloc] init];
    [saveSpriteArray addObject:testSprite];
    savedSpriteData = [NSKeyedArchiver archivedDataWithRootObject:saveSpriteArray];
 }

-(void)loadIconSpriteState  {
   [NSKeyedUnarchiver unarchiveObjectWithData:savedSpriteData];
}

-(void)saveAndLoadSpriteState    {
  if ((testSprite.position.x > size.width/2) && !savedState) {
    savedState = YES;
    [self saveIconSpriteState];
}
else if ((testSprite.position.x == 3*size.width/4) && savedState) {
    savedState = NO;
    [self loadIconSpriteState];
    [testSprite runAction:moveTo];
    }
}

@end
编辑

设置异常断点后,我得到了以下错误

Assertion failure in -[CCIconSprite initWithFile:]
指向行中的行:

NSAssert(filename != nil, @"Invalid filename for sprite");

-(id) initWithFile:(NSString*)filename

CCSprite.m类的方法。

只是一种预感,但可能就是这样。当解码字符串时,您应该复制它,因为此时您不拥有它,也没有将它指定给strong或copy属性

- (id)initWithCoder:(NSCoder *)decoder {
   NSString* imageFileName = [[decoder decodeObjectForKey:@"imageFileName"] copy];
   self = [self initWithIconType:imageFileName];
   if (!self) return nil;
   ...
}

如果不是这样,请设置一个断点,并在编码和解码时验证字符串是否正确

它到底在哪里坠毁?如果尚未启用异常断点,请启用该断点。您是否单步查看imageName是否正确编码/解码?您是否知道您正在使用self.position=ccp(iconXPos,iconYPos);在解码Iconxypo之前?你为什么不使用ARC?请做@LearnCos2D:请查看我添加的编辑。我还按照您的建议启用了ARC。关于位置,在使用它们之前我应该如何解码它们?我必须承认,我不太确定我是如何处理这些位置的。你应该设置self.position=ccp(iconXPos,iconYPos);读取变量后,在initWithCoder中。我意识到我在
testSprite
上使用的是
+(id)spriteWithFile:(NSString*)filename
,而不是
+(id)iconWithType:(NSString*)imageName
,因此
imageFileName
nil
。现在可以用了,谢谢。但是现在我想保存上面的
HelloWorldLayer
的状态,这将如何实现?我是否需要从
CCLayer
中创建子类?