使用自定义init进行NSCoding

时间:2011-10-28 06:04:43

标签: objective-c cocos2d-iphone nscoding

我有一个名为“Defense”的类,使用自定义init方法,如下所示:

// initialize the defense unit and add the sprite in the given layer
- (id) initWithType:(DefenseType)tType andInLayer:(CCLayer *)layer {

    NSString       *fileName;
    fileName     = [NSString stringWithUTF8String:defenseStructuresFile[tType]];

    if ( (self = [super initWithFile:fileName]) ) {

        type              =   tType;
        maxHealth         =   defenseStructuresHealth[tType];
        health            =   maxHealth;
        mapRef            =   (SkirmishMap *)layer;        
    }
    return self;
}

现在我正在使我的班级NSCoding兼容,这需要以下两种方法:

- (id) initWithCoder:(NSCoder *)decoder
- (void) encodeWithCoder:(NSCoder *)encoder

当我通常分配一个“防御”实例时,我编码如下:

Defense                 *twr;
twr                 =   [[Defense alloc] initWithType:type andInLayer:mapRef];

当我想恢复已保存的Defense对象实例时,我编码为

twr                 =   [[decoder decodeObjectForKey:kDefense] retain];

但是在上面的代码中,我无法传递“type”和“mapref”参数,这些参数非常需要initialize对象......

防御类派生自CCSprite,由于CCSprite不符合NSCoding,因此可以通过(self = [super initWithFile:fileName])方法调用initWithCoder。但我需要type参数来确定要传递给ccsprite's initWithFile的文件名。

那么在这种情况下我该怎么做? 我应该改变班级设计吗?如果有,怎么样?

任何好的想法/建议都受到高度赞赏......:)

1 个答案:

答案 0 :(得分:2)

您可以这样做:

- (id)initWithCoder:(NSCoder *)decoder
{
    DefenseType earlyType;
    NSString *filename;

    earlyType = [decoder decodeIntegerForKey:@"defense"];

    if (earlyType == somethingIllegal) {
        [self release];
        return nil;
    }

    // Now do something with earlyType do determine filename

    self = [super initWithFilename:filename];
    if (!self) return nil;

    type = earlyType;
    // Decode the rest.

    return self;
}

输入您的方法(即使init)后,始终会设置self。它只是一个变量(或更确切地说:一个参数)。这就是[self release]; return nil;即使在调用super之前也能正常工作的原因。当您致电self = [super initWithFoo:];时,您将覆盖self。这样做是因为你的超类可能会[self release]; return nil;或者分配一个具体的子类并返回它(当使用类集群时)。因此,在调用super的初始化程序之前,覆盖实例变量是不安全的,但是使用普通的堆栈变量(甚至全局变量)是可以的。