Releasing Cocos2d texture atlases - objective-c

How does one release a texture atlas using cocos2d?
I have the following code
NSString *blue= = #"Blue.plist";
CCSpriteBatchNode *blueBatchNode = [CCSpriteBatchNode batchNodeWithFile:#"Blue.png"];
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:blue];
[self.parentScene addChild:blueBatchNode];
How do I release these 2 at a laster stage?

[[CCSpriteFrameCache sharedSpriteFrameCache] removeSpriteFramesFromFile:#"Blue.plist"]

Most if not all CCNode derived objects are auto released. So long as you use convenience methods not alloc init.
e.g.
CCSprite *sprite = [CCSprite spriteWithFrameName:#"blahblah"];
Once your CCLayer removes the batchnode as a child, it should release that object, unless there are somehow some things linking to it, perhaps children that didn't get removed (but they should do).
Failing it being removed when that happens, you can also use purgecacheddata to clear out textures.
[[CCDirector sharedDirector] purgeCachedData];
Purging cached data also removes cached spriteframes as mentioned in the question above.

Related

How to access a SpriteBatchNode from another class? cocos2d

I'm having trouble getting my sprite batch node to work and it's partly because I don't understand the concept complete. The SpriteFrameCache is shared, which makes it easy to access, but the SpriteBatchNode isn't so I don't know the best way to access it from another class.
I have my sprite batch node set up as an instance variable in my main GameplayLayer.m:
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"MyTexture.plist"];
spriteBatchNode = [CCSpriteBatchNode batchNodeWithFile:#"MyTexture.png"];
But then I have a Monster class with animations set up inside the class but the sprites are in the texture that was created in my GameplayLayer class:
CCAnimation *walkAnim = [CCAnimation animation];
[walkAnim addSpriteFrame:[spriteFrameCache spriteFrameByName:#"monster-sprite-walk0.png"]];
//some other code
self.monsterWalkAnimation = [CCRepeatForever actionWithAction:walkAnimationAction];
Which doesn't work, I'm guessing because it has no idea where the texture is. What is the best way to access that sprite batch node, or am I setting this up all wrong?

Why does my NSArray get deallocated?

I'm trying to understand Automatic Reference Counting, as I come from a high-level programming language (Python) and I'm working on a project which use this feature of Objective-C. I often get problems with ARC deallocating objects which I need later, but now I got a concrete example for which I hope I'll get an explanation.
- (void) animateGun:(UIImageView *)gun withFilmStrip:(UIImage *)filmstrip{
NSMutableArray *frames = [[NSMutableArray alloc] init];
NSInteger framesno = filmstrip.size.width / gun_width;
for (int x=0; x<framesno; x++){
CGImageRef cFrame = CGImageCreateWithImageInRect(filmstrip.CGImage, CGRectMake(x * gun_width, 0, gun_width, gun_height));
[frames addObject:[UIImage imageWithCGImage:cFrame]];
CGImageRelease(cFrame);
}
gun.image = [frames objectAtIndex:0];
gun.animationImages = frames;
gun.animationDuration = .8;
gun.animationRepeatCount = 1;
[gun startAnimating];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,(arc4random() % 300)/100 * NSEC_PER_SEC), dispatch_get_current_queue(),^{
[self animateGun:leftGun withFilmStrip:[self getFilmStripForAction:gunShoot andTeam:nil withWeapon:nil]];
});
}
The idea behind this snippet of code is simple: I have a (UIImageView*)gun which I animate with the images stored in (NSMutableArray *)frames, at random times. (UIImage *)filmstrip is just an image which contains all the frames which will be used on animation. The first iteration of animation works, but the problems appears on the second iteration, where I get -[UIImage _isResizable]: message sent to deallocated instance ... or -[UIImage _contentStretchInPixels]: message sent to deallocated instance ... or -[NSArrayI release]: message sent to deallocated instance .... This happens at
gun.animationImages = frames;
but I don't understand why. I'm not requesting a fix for my issue, but just to help me understand what's happening here. Thanks.
ARC is a mechanism that removes the need to manually retain/release objects. Here's a nice site that explains how this works: http://longweekendmobile.com/2011/09/07/objc-automatic-reference-counting-in-xcode-explained/
Try changing "leftGun" for "gun". I think that's probably the one that gets deallocated at some point, if you're using it through an ivar. Otherwise, leftGun simply isn't in the scope.
Here's what it should look like:
In your .h file:
#property (nonatomic, strong) IBOutlet UIImageView *leftGun;
In your .m file:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,(arc4random() % 300)/100 * NSEC_PER_SEC), dispatch_get_current_queue(),^{
[self animateGun:gun withFilmStrip:[self getFilmStripForAction:gunShoot andTeam:nil withWeapon:nil]];
});
Also, not quite sure where "gunShoot" is coming from. Is that supposed to be an enum?
EDIT
Added an example of how the leftGun property should be defined. The reason behind using a property over an ivar is for memory management purposes. If you want to release or destroy an object that is a property, simply set it to nil and the property will take care of releasing the object if it has to.
You may prevent the deallocation of the frames array if you mark it as __block.
__block NSMutableArray *frames = [NSMutableArray array];
see “The __block Storage Type.”

Released array EXC_ACCESS_ERROR and Cocos2D

I recently posted a question here about some memory issues I was having. I've got that fixed now thanks to this wonderful community but I'm facing another problem. I'm using Cocos2d to develop a game and I'm trying to remove a Sprite from and array. The problem arises when I try and release the temporary array I'm using to keep track of the sprites to remove.
NSMutableArray *spritesToRemove = [[NSMutableArray alloc] init];
// Loop through all sprites
for(CSSprite *sprite in _sprites){
if(sprite.toRemove){
[spritesToRemove addObject: sprite];
}
}
// loop through sprites to be removed
for(CSSprite *removeableSprite in spritesToRemove){
[_sprites removeObject: removeableSprite];
// Cocos2d code to remove a sprite
[self removeChild: removeableSprite cleanup: YES];
}
[spritesToRemove release]; // EXC_BAD_ACCESS error
I get a feeling the reason I'm getting the error is because I'm releasing the sprite object in [self removeChild: removeableSprite cleanup: YES]; before actually releasing the array. It all works fine if I remove the line [spritesToRemove release] but I obviously then have a memory leak on my hands.
I've tried moving the removal of the sprites around and I can get the memory thing sorted by completely omitting the line [self removeChild: removeableSprite cleanup: YES]; but then Cocos2d throws the same EXC_BAD_ACCESS error from within CCNode at [child visit]; of -(void) visit
Thanks again for your help :-)
EDIT: I enabled NSZombie and I got this message:
*** -[Sprite release]: message sent to deallocated instance 0xfa94cf0
Which to me kind of suggests my initial thought, somewhere an entry in the array is being released to soon. Would that be correct? If so is there anyway for me to find out where?
I managed to find the issue (and to be honest I feel a little silly :-P ). I was releasing the sprite manually once I added it to the array, which wasn't in the code provided so you guys couldn't have found it. The sprite was already set up to be autoreleased and thus was being cleared twice - causing my error.

copy a sprite pointer to keep him const?

i have this function :
-(void)blink:(CCSprite *)sprite
{
CCSprite *blinker=[sprite copy]; // i have add that to prevent sprite from change.
it gets a sprite and do animation on it, but sprite is keep changing all time cause its a pointer, so my function keep get a different sprites -WHICH I DONT WANT.
i was trying to copy it to another ccsprite, but its crashes.
whats wrong here ?
is that because i havnt release it ?
thanks alot
Can you post the code where call the blink method?
Maybe you can try this:
-(void) blink:(CCSprite*)sprite {
[sprite retain];
// Do some stuff with the sprite here
[sprite release];
}
However, functions should be called with thread-safe parameters so they don't get deallocated during the functions execution.

iOS: Xcode 4.2: Leaks Instrument says I have a leak with my NSMutableArray and NSMutableDictionary but I don't see where

I have the following simple code to track MKAnnotations in my MKMapView. I create the annotations in a loop through my list of locations I want to track. I add the annotations to my collection classes, an NSMutableDictionary and NSMutableArray, which are declared properties (not using ARC but am using Xcode 4.2 so using "strong" instead of retain since they are supposedly synonymous; for future compatibility with ARC).
If I call this routine a second time (say when the list of locations gets updated), the Leaks Instrument claims that the annotations are leaking, as well as the collection objects themselves. (I get a single NSMUtableDictionary in my leak list with the stack trace pointing to the line where the dictionary is created and set into my property, we well as a number of small leaks that match up to the annotations, and complaints about both the NSMutableArray and NSMutableDictionary). However, I don't see any violations of the memory management rules. I have a release paired with my annotation creation through alloc/init. I do an implicit retain through my property "setter" and when the collections are replaced, they should be released and then release all their content objects. If anyone can see where I go wrong, I would appreciate it.
#property(strong, nonatomic) NSMutableArray *annotationList;
#property(strong, nonatomic) NSMutableDictionary *annotationLocations;
.
-(void) createMapAnnotations
{
if ([[self mapView] annotations])
[[self mapView] removeAnnotations:[[self mapView] annotations]];
[self setAnnotationList:[NSMutableArray array]];
[self setAnnotationLocations:[NSMutableDictionary dictionary]];
for (JEstablishmentLocation *loc in [[JLocationManager sharedLocationManager] localLocations])
{
MKPointAnnotation *annotation = [[MKPointAnnotation alloc] init];
[annotation setCoordinate:[[loc estCoordinates] coordinate]];
[[self mapView] addAnnotation:annotation];
[[self annotationList] addObject:[NSDictionary dictionaryWithObject:annotation forKey:[loc estKeyValue]]];
[[self annotationLocations] setObject:loc forKey:[annotation description]];
[annotation release];
}
[self centerOnCurrentLocation];
}
Instruments show where the leaked objects are allocated, it does not show where the leak is happening. I mean, maybe the object that is allocated on the pointed line, cause a leak somewhere else in your code.
I don't know if this may be the case for your code, though.