CCSprites in NSMutableArray does not reappear after scene change - iphone

I am making a game and i am putting CCSprites in a NSMutableArray.
When i start the game for the first time the sprites are appearing on screen, everything seems to work fine.
But when i change to another scene and come back, none of the sprites are visible on screen.
Here below is the code to initialize the Sprites.
-(void spritesInit)
gpsUsersSpritesArray = [[NSMutableArray alloc]init];
for (int i = 0 ; i < [userArray count] ; i++){
playerSprite = [CCSprite spriteWithFile:#"greenspot.png"];
playerSprite.position = ccp( winSize.width/2, winSize.height/2);
[self addChild:playerSprite z:5];
[gpsUsersSpritesArray addObject:playerSprite];
[playerSprite release];
}
}
The above method is run every time the scene is called.
I run the action below on the sprites, that works also fine the first time, but again not when i leave and return to the scene. The sprites seems to be loaded and the code itterates through the NSMutableArray in question without a crash, and this leaves me puzzled.
for (CCSprite *userspot in gpsUsersSpritesArray){
id fadein = [CCFadeTo actionWithDuration:0.05 opacity:255];
id fadeout = [CCFadeTo actionWithDuration:dotFadeTime opacity:30];
id seq2 = [CCSequence actions:fadein, fadeout,nil ];
[userspot runAction:seq2];
}
I have tried to retain the NSMutableArray, but that dit not help either.
Also i have tried to force the sprites to be visible and make sure the opacity of the sprites is set to 255, but still no luck.
I may have overlooked something, but i do not think so.
Who helps me out?
Many thanks in advance.

You should not be releasing your sprite. I would think that would cause a crash but it could account for your issue.
When you create a sprite using something like:
CCSprite* mysprite = [CCSprite spriteWithFile:#"whatever.png"];
You NEVER should be releasing that. When coding in Objective-C the rule to remember when not using ARC is that you release objects that you alloc/init, new, retain, and copy yourself. You don't do that in your example code. Inside that method it calls autorelease, making your release invalid. The same with adding objects to containers. Those containers take care of themselves and you should not be releasing or doing anything to the retain count outside of those containers on their behalf if you are using convenience methods that call autorelease, like you are in this case. That is invalid. It would be fine if you were using, for example, alloc/init rather than the spriteWithFile method.

Related

CGImage/UIImage passing causes EXE-BAD-ACCESS

FIXED: I'm not sure yet why. Code has been updated below, and notes at the bottom
I'm having a very strange error that does not show up on the Simulator (even when running Instruments), unless I turn on all the Zombie and Debug options. However, it will crash the phone after a minute of updates (1 update per second). I have a 2D array that I take a subset of, apply a colormap, and turn into an image (this array changes constantly). Then I pass that image to the model, and the viewcontroller grabs it from the model once it receives notification of an update. I'll layout the 3 classes -Spectrogram, Model, ViewController:
Here are the important bits of each (there is more, but not relevant):
Spectrogram.h (Sorry, I can't get this to indent correctly on here)
#interface: Spectrogram : NSObject
{
NSMutableData *arrayData;
}
//renamed so Xcode allows the object with +1 reference count to be returned
- (CGImageRef)newSpectrogramImage;
Spectrogram.m
#implementation Spectrogram
- (CGImageRef)newSpectrogramImage
{
//slightly reordered
NSMutableData *imageData = [[NSMutableData alloc] init];
...code to go through arrayData and colormap it (get RGB transform) and store in imageData...
CGImageRef arrayImage = nil;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
//specifically tell CGImage there is no alpha channel
CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault | kCGImageAlphaNone;
//Use the toll-free bridge between NSData and CFData
CGDataProviderRef provider = CGDataProviderCreateWithCFData((CFDataRef)imageData);
arrayImage = CGImageCreate((slices-startSlice), bins, 8, 24, 3*(slices-startSlice), colorSpace, bitmapInfo, provider, NULL, false, kCGRenderingIntentDefault); //image is rotated now, so width and height are switched
CGColorSpaceRelease(colorSpace);
CGDataProviderRelease(provider);
CGImageRelease(arrayImage);
[imageData release];
//Pass the CGImageRef with a reference count of 1
return arrayImage;
}
Model.h
#interface: Model : NSManagedObject
{
Spectrogram *spectrogram;
}
//Function the viewController can call to get the update
- (CGImageRef)newSpectrogramImage;
Model.m
#implementation Model
... there is a function that adds new data to the array and notifies all listeners...
- (CGImageRef)newSpectrogramImage {
return [spectrogram newSpectrogramImage];
}
ViewController.h
#interface: ViewController : UIViewController
{
}
//the root controller actually alloc's the record, and sets this property when creating this view
#property (nonatomic, retain) Record *currentRecord;
ViewController.m
#implementation ViewController
#synthesize spectrogramView;
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter ... listen for model updates...
}
//now, the real meat
- (void)recordUpdated:(NSNotification*)notification
{
CALayer *myLayer = self.view.layer;
CGImageRef spectrogramImage = nil;
spectrogramImage = [currentRecord newSpectrogramImage];
myLayer.contents = (id)spectrogramImage;
CGImageRelease(spectrogramImage);
}
I've changed this so many times in the last day trying to hunt down where and why it fails. I've tried passing the CGImageRef instead (but since that isn't an object, I'm worried about making copies of what can be a -huge- image) and it still fails. And it works perfectly in the simulator (will run for dozens of minutes). But fails within a minute on the iphone, or if I turn on the debug options for the simulator (it will fail as soon as the viewcontroller is loaded).
On a side note, that might be of some use. This viewcontroller is loaded as a modal view when the phone is turned sideways (works great). However, I have a lot of NSLogs in there and I see this viewcontroller's dealloc is called before the mainviewcontroller even gets to viewwilldisappear - but it still runs. And then this controller's dealloc is called again when the phone is turned back and the view disappears.
Note
The version that worked well in the simulator passed CGImageRefs all the way to the viewController, instead of UIImages. I've tried at least 50 different combinations of where to create the UIImage from the CGImage, and what's posted above is just one of them (all of them fail eventually, or immediately). Of note, with the code above, if I do add this to the viewController modelUpdated:
CGSize size = currentModel.spectrogramImage.size;
NSLog(#"width: %f", size.width);
and comment out assigning it to the spectrogramView, the width is reported correctly, so the UIImage is getting passed along, it's just not getting retained (This is how I understand the EXE_BAD_ACCESS error).
Also, recently I receive dan EXE_BAD_ACCESS on the
self.spectrogramImage = [spectrogram getSpectrogramImage];
line. So, I think the error may be inside the Spectrogram class. Even though the CGImage and UIImage code was taken from Apple examples.
Fixed notes
I read that setting the contents of the CALayer was a much quicker way to pass a CGImageRef to a view - and no UIImage intermediary. Unfortunately, I only commit working changes, so I can't see every iteration I went through. However, I know that I had something very similar to this several times that kept crashing. The problem was always that as it is currently written, the program would crash with EXE_BAD_ACCESS. And if I upped the reference count (or didn't release it), then it would work perfectly, but the object would leak. I still don't understand how that is possible. To have the difference between a leak, and a BAD ACCESS be a reference count of 1 (and not 2 or more).
I can't answer your specific question, but this might help you know what is going on a little bit better. I have a function "logMemUsage" that outputs your memory usage and shows how much it changed since last time. If you call it once a second or so, you can better understand how memory is being used in your app. If it keeps growing, obviously there's a leak, if it goes up and down as you expect it, that's good, if it doesn't go down when you think it should, you'll see it. It's in github here in Utilities.h/.m
It's hard to figure this out from what you've posted, but why not use properties with retain on all your allocated data? For example, you're returning an autoreleased UIImage from getSpectrogramImage, and it gets stored into Model with the call self.spectrogramImage = [spectrogram getSpectrogramImage];, but there isn't a property for spectrogramImage anywhere I can see, even though you're using the self. mechanism. Is it just that you didn't bother to post it? The way it's written it could be getting autoreleased, and then when you try to use it...

Deleting CCSprites stored in NSMutableArray not working right

Here is what I've tried.
In my init method I initialized the array:
deleteSprites = [[NSMutableArray alloc] initWithCapacity:500];
This is how I added them to the array:
CCSprite *SpriteSave;
SpriteSave = [CCSprite spriteWithBatchNode:Batch rect:CGRectMake(0,0,6,6)];
[Batch addChild:SpriteSave];
[deleteSprites addObject:SpriteSave];
This is how I attempt to remove the sprites:
delCount = 0;
while (delCount < [deleteSprites count])
CCSprite *delSprite = (CCSprite *) [deleteSprites objectAtIndex:delCount];
[delSprite.parent removeChild:delSprite cleanup:YES];
delCount++;
}
[deleteSprites removeAllObjects];
This causes some of the sprites to flip, but they still appear on screen and none are deleted. I've already researched everywhere and although I made my code very similar to others that got it to work, it still won't work for me. I've also already read through the memory management documents and I still don't see what I'm doing wrong. Also I've tried adding the sprites to the userdata of the fixtures they're supposed to be representing and when the fixture is destroyed I once again try to remove the sprite but the same thing happens. Please Help!.
I figured out what it was. I was making a logical error in a few of my if statements and accidentally added the sprites twice. Sorry about that everyone.

iphone object c is object already released

i release an image with [myimageview.image release];
but after the app was in background it comes foreground again it release that image again, so it crash! All my tries to check if the app came from a background did not worked.
So how could i check if an object is already released.. so i dont do it twice?
thankx
chris
EDIT
After several complains about my bad coding :) here an example:
First I initialize an Array with the path to a lot of fullscreen images
Also there are around 10 Different Arrays for 10 different Scenes.
When I put directly the Images in an array it just needed to much memory from the beginning, or when i released a scene totaly , it needed to load the whole image array again and that came to slow. So I just load the path to the images into an array and assign each pic in a loop to my imageview while runtime.
Init once:
imageArray_stand= [[NSArray alloc] initWithObjects:
#"FrankieArmeRaus_0001.jpg",
... up to 60 Images
#"FrankieArmeRaus_0061.jpg",nil];
In a Loop thats called each 1/10 Second:
if ([myimageview.image retainCount] > 1)
//if ( myimageview.image != nil) // does not work = crash
{
[myimageview.image release];
myimageview.image = nil;
}
myimageview.image = [UIImage imageNamed:[imageArray_stand2 objectAtIndex:piccounter-1]];
Problem came, because when the app went into background and than into foreground again it seems to release the image 2 times, so i needed a solution to check that.
I am happy about any solution (just NOW it works) thats better.
Even to load all images completly into an array, but as mentioned it needs to much mem and to reassign while runtime needs to long to load. (1 sec for 50 Images)
Also I needed to RELASE and set to NIL, because otherwise it would even make my memory usage out of limit.
You never, ever, release a property of another object. You release the entire myimageview object, or you just assign to it's properties. How those properties are memory manged is the private business of the myimageview object.
Easiest way is to do something like this:
if (someObject != nil)
{
[someObject release];
someObject = nil;
}
However, I don't think you should be releasing myimageview.image, assuming that myimageview is a UIImageView. The UIImageView is responsible for managing its image; you shouldn't be messing with its retain count.
Maybe what you really want to do is this:
myimageview.image = nil;
This will cause myimageview to release it and stop pointing to the now-invalid memory.
solved it with
if ([myimageview.image retainCount] > 1) [myimageview.image release];

Heeelp! Debugger says "out of scope"!

I just cannot imagine what the hell the problem could be.
I made a pretty app, and decided to use only CALayers to "render".
When I saw that the changes in the position property gets animated, decided to implement a custom getter-setter "abstract" property called tanCenter to set the position without animating.
-(void) setTanCenter: (CGPoint) sentCenter
{
//Remove any transactions.
[CATransaction begin];
[CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];
//Set position.
self.position = sentCenter;
[CATransaction commit];
//Set value.
tanCenter = sentCenter;
}
-(CGPoint) tanCenter { return tanCenter; }
Since I merged this into the project, it crashes without any "understandable" (for me) error message. I can see only those "out of scope"-s. I cant even get this tanCenter property NSLog-ged without crash.
Help me, Obi-Wan Kenobi; you're my only hope.
If you run in the debugger (Command-Y) and make sure you have global breakpoints enabled, the debugger should stop at the place where the crash occurred giving you an idea of what is nil or over-released.
hey I had the same problem till now. Finally I have found my bug after investigating 2 weeks of bug tracking (it really sucks)
maybe my problem helps you:
I started with a TableView that opens on click another view. So I created in:
-(void)tableView:didSelectRowAtIndexPath:
first the controller for the other view and set the value for a global variable:
SomeView *dtview = [[SomeView alloc] initWithNibName:#"SomeView" bundle:nil];
dtview.lblTitle = cl.textLabel.text; // cl is the cell
[self presentModalViewController:dtview animated:NO];
[dtview release];
So opened the other view and done much functions with much memory usage :)
When I after that close the other view and go back to the table and scroll some times the App terminates with the message "out of scope"
I searched really, really long to find out what was the effect. It seems that when the other view is released also the text of the first table is released.
After putting a copy to the call it worked for me:
dtview.lblTitle = [cl.textLabel.text copy];
For int and bool the first solutions works fine, because these aren't objects but for NSObject's you should copy the values to another view.

iPhone UIImage - Image Randomizer Crashes If It Comes Across the Same Image Twice

I am building a game that pulls images randomly. After doing some testing I have realized if the same image is called twice, it crashes. I learned this by after completing the first game, I returned to the games main menu and selected to play again. I ended up getting an image which was already displayed to me in my previous game and a second later my app crashed. I did some testing and made the same image show up twice during my first game, and it crashed a second after the image was displayed a second time.
Here is a sample code. "idNum" and "timer" are declared in the .h file so they are global. As you can see I have NSTimer that runs every second to randomize a new image to be pulled. Works find until an image is trying to be shown for a second time. Say I get a random order of 1,3,2,5,3. It will crash on the second 3.
Can you not call an image twice? I can only think that this is a caching issue, I am not sure how to release the image cache. I get the error objc_msgSend. Sorry not very good at debugging crashes.
//idNum = the randomly generated integer
//pictures are called by numbers ex(1.jpg, 5.jpg)
timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(timeCounter) userInfo:nil repeats:YES];
-(void)timeCounter {
time = time + 1;
idNum = (arc4random() % 5);
NSString * imgIDnum = [[NSString alloc] initWithFormat:#"%d", idNum];
imgMain = [NSString stringWithFormat:#"%#%#", imgIDnum, #".jpg"];
[imgIDnum release];
UIImage * daImg = [UIImage imageNamed:imgMain];
[imgView setImage:daImg];
}
You should provide more information about the crash. Is it in the +imageNamed: line above, or perhaps in -setImage:?
The most likely cause is that you are over-releasing the UIImage. For instance, if you're calling [daImg release] after the above code, then you would get this behavior because you would be over-releasing something that the UIImage class is caching. This wouldn't cause a crash until the situation you describe.
I've seen a really entertaining version of this bug: a teammate of mine was over-releasing an NSNumber (it happened to be for the integer 2 most of the time). NSNumbers are cached internally, so the next time he created an NSNumber for the integer 2, in an unrelated part of the program, it would crash. Any other number was fine, but try to NSLog() a 2, and boom.
Well I am sorry to say that I have fixed the issue and have no idea how. I ended up re-writing majority of that code, adding, removing and changing some snippets around to be more memory management friendly. When I went to run it again things were perfectly fine. Sorry for no solution. If someone else comes across this problem, let me know I will try and help.