Cocos2D calling an object init from a scene layer init - iphone

Hi I'm currently working on an iPhone game, top-down Strategy RPG (kinda like Fire Emblem), I have my tiled map set up, and the gameplay layer and some characters and enemies set up and drawn on the screen and moving around. My question really just to help wrap my head around how I can initialize my characters easliy. My character init is simple, it just loads the animations and set the stats as such:
//Hero Class
-(id)init
{
if(self = [super init])
{
characterClass = kHeroClass;
[self initAnimations];
[self declarePlayer:Hero withLevel:1 withStrength:15 withDefence:14 withMindpower:15 withSpeed:26 withAgility:26 withLuck:12 withEndurance:10 withIntelligence:15 withElement:kFire withStatus:kStatusNormal];
}
return self;
}
and so in the game scene, can I just be like:
(in .h file)
PlayerCharacter *mainChar;
#property(retain)PlayerCharacter *mainChar;
(in .m file)
-(id) init
{
if((self=[super init]))
{
//the usual stuff
mainChar = [MainCharacter init];
return self;
}
}
However, I've seen online and in tutorials people using
MainCharacter *mainChar = [MainCharacter alloc];
would that be the same as
mainChar = [MainCharacter init];
if not could someone help clarify which syntax to use. Thanks very much :D Have a great day!

I think you should consider reading quickly through some introduction tutorials. This one is awesome and will get you used to the syntax and semantics of Objective-C:
http://cocoadevcentral.com/d/learn_objectivec/
alloc will allocate memory for an object and init will set things up like a regular constructor. You will also see initWith... style functions which can also be used like so:
MyObjectClass *instance = [[MyObjectClass alloc] init];
This then needs to be released in the same class it was created in the dealloc method.
As for setting up objects, it's better to not use a really long method name declarePlayer:Hero withLevel... but rather:
Set up the object and then alter properties:
Player *player = [[Player alloc] init];
player.health = 10;
player.armor = 20;
...
Once you become familiar with Objective-C as a language, tacking cocos2d and any other code will be much easier. For that, you can visit the the programming guide and find tutorials around the web like at www.learn-cocos2d.com.

Related

Is this scenario appropriate for a singleton?

Quick question, I've been programming objective-c for about 2 months now, however I am well versed in a number of other languages.
I would like to know if the following situation is appropriate for a singleton, and if so, is there a more appropriate way of handling the initialization of the singleton than my current code?
I have the singleton, enemiesArray that is accessed by a multitude of other classes. This is in my Enemy class, enemy is the direct parent of a number of enemy specific classes. Each enemy specific class accesses initWithSpriteFile during it's own initialization, which in turn adds the enemy to the enemiesArray singleton.
// Singletons
static NSMutableArray *enemiesArray;
// Methods
+(NSMutableArray *) sharedEnemies
{
if (!enemiesArray) { enemiesArray = [[NSMutableArray alloc] init]; }
return enemiesArray;
}
+(id) initWithSpriteFile:(NSString *) spriteFile;
{
if (!enemiesArray) { enemiesArray = [[NSMutableArray alloc] init]; }
if ((self = [super spriteWithFile:spriteFile])) {
[enemiesArray addObject:self];
}
return self;
}
Are enemies CCNode objects (like CCSprite)? Then storing these in a singleton brings with it the very real danger of memory leaks because you might still hold references to a scene's nodes when changing scenes. That would keep the previous scene in memory. You should put that code in your scene's class instead. No need to use a singleton here.

Static Analyzer showing wrong leak?? (XCode 4.0, iOS 4.3 and above)

Happy November to all,
Well I tried Xcode Build and analyze on my project, and it showed some unusual leaks, which I couldn't quite accept with my knowledge of Objective C.
So I decided to put up a test project and ask here..
MemoryTestController.h
#interface MemoryTestController : UIViewController{
UIImageView *tstImageView;
}
#property(nonatomic,retain) UIImageView *tstImageView;
#end
MemoryTestController.m
#implementation MemoryTestController
#synthesize tstImageView;
- (void)viewDidLoad{
[super viewDidLoad];
self.tstImageView = [[UIImageView alloc] //<==This object is leaking
initWithFrame:<SomeFrame>];
self.tstImageView.image = [UIImage imageNamed:#"SomeImage.png"];
[self.view addSubview:tstImageView];
[tstImageView release];
}
-(void)dealloc{
[tstImageView release];
[super dealloc];
}
#end
When I try Build and analyze, clang static analyzer say
Potential leak of an object at line xx
And the culprit line is
self.tstImageView = [[UIImageView alloc]initWithFrame:<SomeFrame>];
I think I am releasing once for every time I am allocing/retaining. Am I missing something, or Static analyzer has some bugs?
EDIT : Is there any leak there?
Well I run the above project using Leak tool in instrument..It didn't show any leak even though I tried many times..Whom should I believe? Static analyzer or Leak instrument?
your problem is how you release it:
- (void)viewDidLoad{
[super viewDidLoad];
self.tstImageView = [[UIImageView alloc] //<==This object is leaking
initWithFrame:<SomeFrame>];
self.tstImageView.image = [UIImage imageNamed:#"SomeImage.png"];
[self.view addSubview:tstImageView];
[tstImageView release]; // << here
}
you should do it this way:
- (void)viewDidLoad{
[super viewDidLoad];
UIImageView * imageView = [[UIImageView alloc] initWithFrame:<SomeFrame>];
imageView.image = [UIImage imageNamed:#"SomeImage.png"];
self.tstImageView = imageView;
[imageView release];
[self.view addSubview:self.tstImageView];
}
The checker is correct because it cannot assume that the variable is identical to the one you set. Therefore, the form you use in the OP could introduce a reference count imbalance because the ivar's value may not be what you assigned to it by the time you message release upon the ivar.
These cases are not likely for a UIImageView, and quite unlikely in the context of your program, but these examples should give you an idea as to why the checker assumes that object->ivar associations shall not be trusted:
Between creation of the image view and the message to release it via the ivar, you have:
self.tstImageView = [[UIImageView alloc] initWithFrame:<SomeFrame>];
self.tstImageView.image = [UIImage imageNamed:#"SomeImage.png"];
[self.view addSubview:tstImageView];
1) assignment of the image view via the setter
2) access of the image view via the getter
3) direct access of the ivar, when adding to self.view
the setter may have taken a copied or used a cached value. UIImageView is a bad example, but the checker does not know how types are generally passed around - even if it did, it would (at times) make unsafe assumptions.
the simplest example would be:
- (void)setName:(NSString *)inName {
NSString * prev = name;
if (inName == prev) return;
if (0 == [inName count]) name = #"";
else name = [inName copy];
[prev release];
}
the value held by the ivar could change in the meantime. not likely an issue in this case, but let's say that adding the image view as the subview could end up calling back and altering self in the process/effect of adding the subview, and replacing or removing the image view you passed. In that case, the variable view you passed would leak and the view it replaced it with would have a negative imbalance.
Neither of those are likely to happen in your example, but it does happen in real world programs, and the checker is correctly evaluating based on locality, not property (the checker can't assume much of what happens inside a method call). It also encourages one good idiomatic style in this case.
EDIT : Is there any leak there?
Well I run the above project using
Leak tool in instrument..It didn't shown any leak even though I tried
it many times..Whom should I believe? Static analyzer or Leak
instrument?
The static analyzer says there is a potential leak because it is unable to guarantee the reference/allocation it follows is correctly retained/released. You can guarantee that reference counting is correct and please the static analyzer by changing you program to look like I wrote it in my example.
The way you have written it has made it impossible for the analyzer to follow the reference.
If you have no leaks and no zombies, then there is not a leak. But the solution is easy to fix - and programs have a way of changing during development. It's much easier to use the form I posted so it is easier for the toolset and for you to verify the program is correct. The static analyzer is not always correct, but you should adjust your programs to please it because static analysis is very useful. The program I posted is also easier for a human to understand and confirm that it is correct.
when you declare a property with retain like this
#property(nonatomic,retain) UIImageView *tstImageView;
a setter is added that will incr the retainCount when you assign to the property. When you do as below the object you created has already a retainCount == 1
self.tstImageView = [[UIImageView alloc]
initWithFrame:<SomeFrame>];
so the tstImageView object has 2 in retainCount.
do instead
UIImageView* view = [[UIImageView alloc] initWithFrame:<SomeFrame>];
self.tstImageView = view;
[view release];
then, although unrelated to your leak when you release it write like this instead
self.tstImageView = nil;
since the setter will then will properly set the retainCount

Why do we need a temporary object?

As I have seen in many examples, first they allocate memory for the temporary object and later the same object is assigned to self. For example, I have a code snippet here :
-(void)viewDidLoad {
[super viewDidLoad];
Movie *newMovie = [[[Movie alloc] initWithTitle:#"Iron Man"
boxOfficeGross:[NSNumber numberWithFloat:650000000.00]
summary:#"Smart guy makes cool armor"] autorelease];
self.movie = newMovie;
}
Why cant we perform like:
self.movie =[[[Movie alloc] initWithTitle:#"Iron Man"
boxOfficeGross:[NSNumber numberWithFloat:650000000.00]
summary:#"Smart guy makes cool armor"] autorelease];
Both are essentially the same. They adhere to the ownership clause – You release what create/retain. The difference, though not so obvious here, is that the time it takes for an autoreleased object to be released. Say, if loads of such autoreleased objects lingered around in the memory, this could create memory problems. If we released them and their retain count is zero, they are immediately deallocated and memory is freed up.
You don't need the temporary object. Your suggestion is perfectly valid.
However, if you need to set properties or call methods after creating the object, using a temporary object may be a little nicer than calling self.movie multiple times:
Movie *newMovie = [[[Movie alloc] initWithTitle:#"Iron Man" boxOfficeGross:[NSNumber numberWithFloat:650000000.00] summary:#"Smart guy makes cool armor" ] autorelease];
newMovie.rating = 4;
[newMovie fetchImageFromServer];
self.movie = newMovie;
Personally, I do not use autorelease in that scenario, but that's more a style preference:
Movie *newMovie = [[Movie alloc] initWithTitle:#"Iron Man" boxOfficeGross:[NSNumber numberWithFloat:650000000.00] summary:#"Smart guy makes cool armor" ];
newMovie.rating = 4;
[newMovie fetchImageFromServer];
self.movie = newMovie;
[newMovie release];

NSMutableArray and memory dealloc

Im making an app for the iphone using cocos2d and i am trying to figure out the best approach for removing items from a NSmutableArray and from the layer at the same time.
What i mean by this is that the objects within the array inherit from ccNode and contain a ccsprite which i have added as a child to the cclayer. The below code is in a cclayer that has the nsmutablearray called bonusicons.
-(void) AddNewBonusIcon: (int) colour :(int) pos{
BonusIcon *newbonus;
CGSize winSize = [[CCDirector sharedDirector] winSize];
int maxX = winSize.width;
int maxY = winSize.height;
int posX, posY;
newbonus = [[BonusIcon alloc] init];
[newbonus setBonusColour: colour];
int bonusOffset = 0;
posX = anchorX;
posY = anchorY;
bonusOffset = [bonusIcons count]*([newbonus.bonus_sprite boundingBox].size.width/2 + 12);
newbonus.bonus_sprite.position = ccp(posX+bonusOffset,posY);
[newbonus.bonus_sprite setTag:pos];
[self addChild:newbonus.bonus_sprite];
[bonusIcons addObject:newbonus ];
[newbonus release];
}
This appears to do what i want for adding the objects sprite to screen and adding the objects to the nsmutablearray. Now of course this is probably not the correct way to do it so shout at me if not!
next i try to delete the objects from the array and from the screen. I can delete them from the array with no problems i just do the following
for (int i = INITIAL_BONUSES-1; i>=0; i--) {
[bonusIcons removeObjectAtIndex:i];
}
this of course leaves the sprites on screen. so how do i approach what i am trying to do so that i can remove both the sprites from screen and the objects from array that the sprite is associated with. I can remove the sprites from the screen by using the tags and typing
[self removeChildByTag:i cleanup:YES]; but then i get errors when trying to remove items from the array . i assume because i have deleted a part of the object already and the dealloc of the ccnode can no longer find the sprite to release?
so any pointers/tips etc of how i should be doing this would be much appreciated. I have read a bunch of stuff on memory management which i believe is my current issue but i just dont seem to be getting it right.
thanks all
edit: ok since posting this i have removed the sprite dealloc from the ccnode itself and added it to the cclayer above it. This has stopped the crashing so i guess i was right with the problem i was having. I of course do not think the way i solved it is the most ideal way but it will do until i find a better way.
You don't have it in the code you posted, but your question seems to strongly imply that you are calling dealloc. The only place you should ever call dealloc is [super dealloc] at the end of a class's dealloc method. Calling it on anything but super or in any other place is wrong and will lead to errors about prematurely deallocated objects (because, well, that's what it does).
If this is what you're doing, I strongly suggest you read Apple's memory management guide. It lays out how memory management works in Cocoa very simply yet thoroughly.

Initialize a class only once

I have a class that contains a few instance methods which need to be called from another class. I know how to do that -
TimeFormatter *myTimeFormatter = [[TimeFormatter alloc] init];
[myTimeFormatter formatTime:time];
However, I don't want to have to alloc and init TimeFormatter every time I need to call one of its methods. (I need to call TimeFormatter's methods from various methods in another class).
I tried putting
TimeFormatter *myTimeFormatter = [[TimeFormatter alloc] init];
"by itself", or not in any blocks, but when I compile, I get an "initializer element is not constant" error.
Any input is greatly appreciated!
You can use the singleton pattern. You can read more about it here.
Specifically, you'd do something like:
static TimeFormatter* gSharedTimeFormatter = nil;
#implementation TimeFormatter
+ (TimeFormatter*)sharedTimeFormatter {
if (!gSharedTimeFormatter) {
#synchronized(self) {
if (!gSharedTimeFormatter) {
gSharedTimeFormatter = [[TimeFormatter alloc] init];
}
}
}
return gSharedTimeFormatter;
}
...
#end
Notice that we check if the variable is null, and if it is, we take a lock, and check again. This way, we incur the locking cost only on the allocation path, which happens only once in the program. This pattern is known as double-checked locking.
However, I don't want to have to alloc and init TimeFormatter every time I need to call one of its methods. (I need to call TimeFormatter's methods from various methods in another class).
I think it's worth clarifying some OOP terminology here.
The reason you need to alloc and init TimeFormatter is because your methods are instance methods. Because they're instance methods, you need an instance, and that's what alloc and init provide. Then you call your methods on (send messages to) the instance ([myTimeFormatter formatTimeString:…]).
The advantage of allowing instances is that you can keep state and settings in each instance, in instance variables, and make the latter into publicly-visible properties. Then you can deliberately have multiple instances, each having its own settings configured by whatever's using that instance.
If you don't need that functionality, you don't need to make these instance methods. You can make them class methods or even C functions, and then you don't need a TimeFormatter instance. With class methods, you send messages directly to the class ([TimeFormatter formatTimeString:…]).
And if you do want settings shared among all instances (and you don't have any state to keep), then you're right that you can just have one instance—a singleton.
The reason for that parenthesis is that shared state is bad, especially if two threads may use the time formatter concurrently. (For that matter, you could say that about settings, too. What if one thread wants seconds and the other doesn't? What if one wants 24-hour and the other wants 12-hour?) Better to have each thread use its own time formatter, so that they don't get tripped up by each other's state.
(BTW, if TimeFormatter is the actual name of your class: You are aware of NSDateFormatter, right? It does let you only format/parse the time.)
Here's a detail example of a sharedMethod. Credit goes here
#implementation SearchData
#synthesize searchDict;
#synthesize searchArray;
- (id)init {
if (self = [super init]) {
NSString *path = [[NSBundle mainBundle] bundlePath];
NSString *finalPath = [path stringByAppendingPathComponent:#"searches.plist"];
searchDict = [[NSDictionary alloc] initWithContentsOfFile:finalPath];
searchArray = [[searchDict allKeys] retain];
}
return self;
}
- (void)dealloc {
[searchDict release];
[searchArray release];
[super dealloc];
}
static SearchData *sharedSingleton = NULL;
+ (SearchData *)sharedSearchData {
#synchronized(self) {
if (sharedSingleton == NULL)
sharedSingleton = [[self alloc] init];
}
return(sharedSingleton);
}
#end
A very nice, and easy, way to setup a Singleton is to use Matt Gallager's SYNTHESIZE_SINGLETON_FOR_CLASS.
It sounds like you want to make TimeFormatter a singleton, where only one instance can be created. Objective-C doesn't make this super easy, but basically you can expose a static method that returns a pointer to TimeFormatter. This pointer will be allocated and initialized the first time in, and every time after that same pointer can be used. This question has some examples of creating a singleton in Objective-C.
You are trying to declare your variable outside the class? If to do it the way you want to do it you gotta declare it as static so
static TimeFormatter *myFormatter=...
From the name of the class though i dont see why you would wnat to keep one instance of your class... you can also do this with a singleton as described above, that is if you want to keep one instance of your class for the app as a whole.