NSMutableArray

This topic contains 23 replies, has 7 voices, and was last updated by  Mesozoic 4 years, 7 months ago.

Viewing 24 posts - 1 through 24 (of 24 total)
Author Posts
Author Posts
August 25, 2009 at 7:23 pm #216985

gizzerd91
@gizzerd91

I’m using an NSMutableArray to keep track of all the bullets that are flying around in my game. The only trouble is, whenever I go to add a bullet object (an instance of the class Bullet I wrote to hold all the necessary data: speed, position, and damage) to my NSMutableArray, the simulator freezes and dies. Here’s the relevant code chunks:

in GameScene.h:

NSMutableArray *bullets;

in GameScene.m:

-(id) init {

//Some other stuff

//I figured I should cast the array some how, and cause Apple’s APIs didn’t specify, I figured I’d make it with an object.

Bullet *cast = [[Bullet alloc] init];

bullets = [NSMutableArray arrayWithObject:cast];

[bullets removeLastObject];

}

-(void) addBulletPos:(CGPoint)pos Angle:(CGFloat)ang Speed:(CGFloat)vel {

Bullet *newB = [[Bullet alloc] init];

ang /= 180;

ang *= 3.14159;

CGFloat VelX = cos(ang)*vel;

CGFloat VelY = sin(ang)*vel;

[newB SetPosX:pos.x PosY:pos.y VelX:VelX VelY:VelY];

//All of these functions run fine, until this one, and then the whole thing crashes

[bullets addObject:newB];

}

What’s wrong? How can I fix this?

August 25, 2009 at 7:35 pm #258217

ob1
@ob1

Your “bullets” array is autoreleased.

Allocate it that way:

bullets = [[NSMutableArray alloc] init]; // or is it initWithCapacity

No need to add and remove an object.

Don’t forget to release the array in the dealloc method.

August 25, 2009 at 7:36 pm #258218

jd
Participant
@jd

You can just declare NSMutableArray *bullets like you did. It will accept any object you give it. You don’t have to do arrayWithObject or anything, just alloc init the array. If you still get an error, can you post the error you see in the console? And also show the code that calls addBulletPos.

August 25, 2009 at 7:39 pm #258219

ob1
@ob1

Oh and sorry, but don’t listen to what jd said (Sorry, jd, not trying to offense you, but what you said is wrong and might confuse him even more).

August 25, 2009 at 7:43 pm #258220

jd
Participant
@jd

What was wrong? I said what you said, just not as clear i guess.

August 25, 2009 at 7:46 pm #258221

ob1
@ob1

“Declare” is what you do in the .h

You still need to “instanciate” in the .m

And he can’t just instanticiate the way he did (with an autoreleasing class method).

Well, reading several times what you wrote, you might have said the same thing as me in the end :-D, but I first understood as “just declare the variable and then you can add any object to the Array”.

August 25, 2009 at 7:49 pm #258222

cjl
Participant
@cjl

Alternatively, couldn’t he just add a retain to his code?

bullets = [[NSMutableArray arrayWithObject:cast] retain];

I’m not really sure, just guessing.

August 25, 2009 at 7:49 pm #258223

ob1
@ob1

He probably could… but what’s the point ?

August 25, 2009 at 7:53 pm #258224

cjl
Participant
@cjl

No point, just that sometimes “There’s More Than One Way To Do It.”

August 25, 2009 at 7:56 pm #258225

ob1
@ob1

Well,

In that case I think that getting an autoreleased array prefilled with an object in order to retain the array and remove the object is the wrong way to do it.

August 25, 2009 at 8:09 pm #258226

gizzerd91
@gizzerd91

I did what you said (i think) but I still have the crashing problem. Here’s my new code (what I’ve changed from my previous post):

GameScene.m:

-(id) init {

bullets = [NSMutableArray arrayWithCapacity:0];

}

-(void) dealloc {

[bullets dealloc];

}

Here’s the test code that calls the function (I put it in my animation loop so that it will call more than once):

- (void) animLoop {

if (bottomAnimCounter >= 6) {

//Here’s the call function

[self addBulletPos:ccp(240,320) Angle:45.0 Speed:3.0];

bottomAnimCounter = 0;

bottomDirection ++;

if (bottomDirection >= 7) {

bottomDirection = 0;

}

}

[self updateBottomHalf];

//[self updateBullets];

}

August 25, 2009 at 8:56 pm #258227

cjl
Participant
@cjl

@gizzer91

I don’t think you’re doing it right. Read this:

http://memo.tv/memory_management_with_objective_c_cocoa_iphone

Or this:

http://developer.apple.com/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html#//apple_ref/doc/uid/20000994-BAJHFBGH

If I have this right, then ‘arrayWithCapacity’ is a convenience method, and you need to retain it if you want it to be around after your ‘init’ method.

Also, see ob1′s answer for another way of doing it.

August 25, 2009 at 9:25 pm #258228

ob1
@ob1

@gizzerd91: You are pulling our leg right ?

Little rant… I will never understand why people will try to write Cocos2D games (which is in my opinion not a trivial task), when they can’t bother first to learn the language (there are very good books on objective-C which explain memory management very well) or simply copy a line of code.

oh and it’s RELEASE not DEALLOC I said to do in the dealloc method too.

August 26, 2009 at 3:29 am #258229

gizzerd91
@gizzerd91

aaaah. well now I feel like an idiot. I knew I was doing something wrong.

August 26, 2009 at 3:30 am #258230

gizzerd91
@gizzerd91

I typed the post wrong, actually. I didn’t copy paste like I should have.

August 26, 2009 at 4:19 am #258231

gizzerd91
@gizzerd91

Ok, well I can’t say how sorry I am for the stupid behavior (not to mention a triple post! this forum desperately needs an edit button). I’ve been programming for 6 years now, but this is only my second week with Obj C, so I’m still very much working out the kinks. I fixed my last problem, and have learned alot about memory management, but now I have one more very Cocos2D related question. So in tandom with my NSMutableArray of bullet information, I have an array of identical length that holds all the sprites. A key functionality with bullets is to be able to delete them when they hit something, and that works fine for the information class, but when I go to [bulletSprites removeObjectAtIndex:i] it crashes on me. Here’s the code for creating the sprites and putting them in an array:

Sprite *newBullet = [Sprite spriteWithFile:@"Bullet.png"];

//I have a sneaking suspicion all my troubles are coming from the following line.

//How do I un-child the sprite so that I can safely kill it without throwing errors?

[self addChild:newBullet z:3];

[newBullet setPosition:pos];

[bulletSprites addObject: newBullet];

//A product of my newfound knowledge, I now know that when you pass an object to an array, it retains it,

//so now I can safely release

[newBullet release];

And here’s the line that’s giving me all this trouble:

[bulletSprites removeObjectAtIndex:i];

August 26, 2009 at 5:03 am #258232

jd
Participant
@jd

Remove from the array, then release. What happened is you released the object and the array still had the pointer – that now points to garbage.

Check out this blog and look for bullet because you probably want to reuse your bullets.

August 26, 2009 at 5:19 am #258233

Mesozoic
@mesozoic

Yeah you’re doing an extra release. Since you didn’t do a retain that release is killing your bullet.

August 26, 2009 at 5:25 am #258234

allenfjordan
Participant
@allenfjordan

No need to get so feisty, people. The fun of cocos2d and iPhone programming is diving right in and sorting things out as you go. Memory management is always an odd thing to learn.

Anyways gizzerd91, try your array initialization/dealloc like this:

-(id) init {

bullets = [[NSMutableArray arrayWithCapacity:0] retain];

}

-(void) dealloc {

[bullets release];

[super dealloc];

}

or, alternately like this:

-(id) init {

bullets = [[NSMutableArray alloc] init];

}

-(void) dealloc {

[bullets release];

[super dealloc];

}

Generally if you create an object using a convenience method (i.e. something that doesn’t involve alloc and init in some way), it will be “autoreleased” and will only last in the scope of the autorelease pool (unless you pass it to something else that will retain it), which I believe ends when the init method finishes (not sure exactly where). To keep your autoreleased object alive, the retain count must be incremented by calling ‘retain’ before the method ends. Be sure to release any retained objects in dealloc to prevent memory leaks.

edit: Oops, looks like a few more replies got in before mine. I hope this was somewhat helpful, at least. Good luck with Objective C… it’s a real oddball language.

August 26, 2009 at 5:44 am #258235

gizzerd91
@gizzerd91

Alright I think I have a working stopgap measure. If I don’t release it immediately, it wont crash later, but it also won’t just disappear. To make it disappear (and for speed, I found a way to do this with normal sprites) I have switched over to AtlasSprites, and I just remove the bullets from the children of the AtlasSpriteManager. The only trouble with that is when I looked it up in the APIs to figure out how to do it, it warned me that removing children is very slow. Is there a faster way to make a sprite disappear (is it more efficient if I just move it off screen)?

August 26, 2009 at 5:46 am #258236

jd
Participant
@jd

Yes. Move them offscreen. It’s very quick.

August 26, 2009 at 6:30 am #258237

ob1
@ob1

Sprite *newBullet = [Sprite spriteWithFile:@"Bullet.png"];

Same problem as before. “spriteWithFile” is a convenience method, it autoreleases the object. So releasing your object after is wrong.

Please get a nice book like:

http://www.amazon.com/Cocoa-Programming-Mac-OS-3rd/dp/0321503619/ref=sr_1_1?ie=UTF8&s=books&qid=1251267972&sr=8-1

> . Is there a faster way to make a sprite disappear (is it more efficient if I just move it off screen)?

[Sprite setVisible = NO];

August 26, 2009 at 10:50 am #258238

adunsmoor
Participant
@adunsmoor

The Stanford iphone classes have a pretty good introduction to memory management and object ownership issues. Check out Lecture 3 at http://www.stanford.edu/class/cs193p/cgi-bin/index.php. The supporting slides are pretty good on their own, too.

August 26, 2009 at 8:33 pm #258239

Mesozoic
@mesozoic

You can also run a FadeOut action on them to make them dissapear, moving their position offscreen is probably faster though not sure.

Viewing 24 posts - 1 through 24 (of 24 total)

You must be logged in to reply to this topic.