0
votes

I'm very new with objective-C, and I am trying to implement a 'factory' style class extending a cocos2D class called CCSprite.

I want there to be a class Monster which extends CCSprite that will create and issue sprites with unique IDs so that I may call and manipulate the generated sprites later on; I am extending CCSprite to add an instance_id property and a static global_id variable.

I want to be able to use all the CCSprite constructors such as spriteWithImageNamed along with all the other functions CCSprite has, the problem is that my instance_id isn't being assigned/incremented properly(It's always 0), and I don't really know where to start to fix this.

Here is what I have:

Monster.h:

#import "CCSprite.h"

@interface Monster : CCSprite

@property (nonatomic, readonly) int instance_id;

@end

Monster.m:

#import "Monster.h"

static int global_id = 0;

@implementation Monster:CCSprite

@synthesize instance_id;


-(id) init{
    self = [super init];

    if(self){
        instance_id = global_id;
        global_id++;
    }
    return self;
}

@end

Is the init function called every time any constructor is called? (eg spriteWithImageNamed)?

How do I ensure my extended properties and variables are applied when I call the parent class's functions?

3
note that @synthesize is superfluous, Xcode will automatically create the ivar for you with the same name as the property but prefixed with underscore, in this case: _instance_id - LearnCocos2D

3 Answers

1
votes

In Objective-C, a class's designated initializer is the one that other initializers are supposed to call into. For many classes, this is indeed init. According to the Cocos2D documentation, however, init is not the designated initializer for CCSprite. Instead, the designated initializer is:

- (id)initWithTexture:(CCTexture *)texture rect:(CGRect)rect rotated:(BOOL)rotated

So that is the method you need to override if you want all the other initializers to call your version.

(If you want to confirm for yourself that this works, you can put a log statement or breakpoint in your implementation of the designated initializer, then call other initializers and make sure the designated initializer is called.)

0
votes

Your init method may or not be called depending on what init these factory methods are using internally. For example, initWithFile may call self = [super init] instead of self = [self init], in which case your implementation will not be called. You can ensure that your initialization is always performed by overriding all init methods of all superclasses and do your necessary setup. Also keep in mind that you can also override any of the factory methods, where you can get the object from calling super, and then assign it's id property before returning.

0
votes

looking at CCSprite it seems that every factory method like +(id)spriteWith* calls an initWith* method

and every initWith* method at the end of the chain calls [self init]

so if you override the init method as you do in monster.m you are ok!

by the way, if you want to create your sprite using a factory method do not call [CCSprite spriteWith*], call [Monster spriteWith*] instead

best regards