使用自定义 init 进行 NSCoding

发布于 2024-12-12 05:53:34 字数 1482 浏览 0 评论 0原文

我有一个名为“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 兼容,这需要以下 2 个方法:

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

当我通常分配“Defense”的实例时,我代码如下:

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

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

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

但在上面的代码中,我无法传递“type”和“mapref”参数,这些参数是初始化所必需的> 对象...

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

那么在这种情况下我该怎么办呢? 我应该改变我的课程设计吗?如果是,怎么办?

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

I have a class named "Defense" with custom init method as below:

// 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;
}

now i am making my class NSCoding compatible, which requires the following 2 methods:

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

When I normally allocate an instance of "Defense", I code as follows:

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

and when I want to restore a saved instance of Defense object I code as

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

But in the above code I cant pass the "type" and "mapref" parameters, which are very much required to initialize the object...

The Defense class derives from CCSprite and since CCSprite doesn't conform to NSCoding, it is fine to call (self = [super initWithFile:fileName]) from my initWithCoder method. But I require the type parameter to determine the filename to be passed to ccsprite's initWithFile.

So what would I do in this situation?
Should I change my class design? if yes, how?

Any good ideas/suggestions are highly appreciated... :)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

2024-12-19 05:53:34

您可以执行以下操作:

- (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 的初始化程序之前,覆盖实例变量是不安全的,但使用普通的堆栈变量(甚至全局变量)是可以的。

You can do something like this:

- (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;
}

When your methods are entered (even init's) then self is always set. And it's just a variable (or to be more precise: an argument). This is why [self release]; return nil; will work even before calling super. When you call self = [super initWithFoo:]; you're overwriting self. This is done because your super class might do [self release]; return nil; or allocate a concrete subclass and return that instead (when using a class cluster). So before you call super's initializer, it's not safe to overwrite instance variables, but it's OK to use normal stack variables (or even global variables).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文