1

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... :)

1 Answer 1

2

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).

Sign up to request clarification or add additional context in comments.

2 Comments

thanks a lot ur answer :) i dont think i understood ur answer exactly. But i learned "self" is not some magic, but just another variable. and regarding my problem, u said like "defensetype" should be saved and restored, instead of passing from the owner object. and yeah that will work i suppose.. thx again :)
it worked by encoding and decoding the defensetype inside the defense class, in case initWithCoder is called. For normal allocation, i use my old initWithType: andInLayer:

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.