Deleting CCSprites stored in NSMutableArray not working right - iphone

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.

Related

CCSprites in NSMutableArray does not reappear after scene change

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.

LevelHelper collision not working

This problem has stumped me for two nights now, I cannot simply have two LHSprites collide with each other using level helper collision. I have checked the docs multiple times to check if I was missing something, but i cannot see it.
In the console of xCode, it logs:
LevelHelper WARNING: Please call useLevelHelperCollisionHandling after addObjectsToWorld
2013-04-24 20:33:04.537 Monkeys2D[1322:c07]
LevelHelper WARNING: Please call registerPostCollisionCallbackBetweenTagA after useLevelHelperCollisionHandling
But as you can see in my code below, I am correctly doing what it is warning me that I am not.
-(id) init
{
if( (self=[super init])) {
self.isTouchEnabled = YES;
loader = [[LevelHelperLoader alloc]initWithContentOfFile:#"Level1"];
[loader addObjectsToWorld:world cocos2dLayer:self];
[loader useLevelHelperCollisionHandling];
[loader registerPostCollisionCallbackBetweenTagA:MONKEY andTagB:SINGLEBANANA idListener:self selListener:#selector(collision)];
}
return self;
}
My problem is that the collision will NOT register, it acts as if nothing is even happening when the MONKEY and the SINGLEBANANA collide.
Any help would be greatly appreciated!
Turns out i needed to add an update method and implement some other box2d stuff, visit the level helper docs & forum to see.

NSMutableArray Difficulty

If you wanna see the code Im having problem with, here is the link:
Code
My question is connected with my past question.
I'm really having problem with my NSMutableArray, I'm currently using iCarousel for my slotMachine object(slot1 and slot2). My app works this way:
From PhotoViewController I made a view that has thumbnail images, then assign its frame with button. So if 1 image was pressed, it will save that integer via NSUserDefaults.
Then I will retrieve it in my carouselViewController
Im thinking of adjusting the array but I can't.
I also have tried my question here:
Comparing with NSMutableArray
If only I can do it the same as Array 2 it would be much easy, but still not working.
(ADDITIONAL INFO:)
I have done it this way, have a Viewcontroller that contains the UIImageView with a button in it, so when the user taps it, my CustomPicker pops up. My CustomPicker contains the image on what the user have picked on the camera roll. So each button has a specific value sent to my iCarouselView using NSUserDefaults. carousel1 for First slot and carousel2 for Second slot.
Here is what I wanna do: I want to forcefully make it stop to the index the user picks. (Which Im doing in my carouselDidEndScrollingAnimtaion)
In my carouselDidEndScrollingAnimation method i tested all of my condition(individually) it works perfectly in terms of comparing.
Then when I combine the conditions, the first Two comparison or STOP is RIGHT, but the next two are always wrong. Or sometimes Got mixed up.
I need to scroll the two specific indexes/integer which was User Picked( I already done that) was able to scroll 2 pairs of them but then the next two were always wrong because I think there indexes were adjusting.
PICTURES:
Image Below is my PhotoViewController which contained the Comparing Stage SETTING of my game.UIImageVIew with UIButton.Image that will be put in the number according to it will be Forcefully and should be forcefully shown.
When my iCarousel start then it stops for example in the image below(Which is not the same as the above):
Will be forcefully scroll to the inputted image in the PhotoViewController
Into:
Summary:
Its like this. I have a settingsView from there, I will import my images(Multiple) for Slot1 & Slot2.
Then in another View the PhotoViewController that is where the image above is shown. THe first column corresponds to 1st slot followed by the 2nd slot. if a view is pressed (for example No. 1 of Slot 1 it will load a thumbnail of images loading the images picked from Picker for the Slot 1.
You will have to do it 4 times(pair) ----> The displayed here I get their indexes via NSUserDefaults via button.tag then send to iCarouselView.
Then when you are done (pressed Done button) it will go to iCarouselView then, as shown above thats the view of it.
When pressed it will spin for couple of seconds, then when finished but not stop at the user picked in the PhotoView it will forcefully scroll to that index.
QUESTION:
Is there a way to make my array or my iCarousel.view not adjust their indexes when Im deleting. To still retain my indexes the right way. Or are there other solution like adjusting my array, the same as adjusting my PhotoViewController picked indexes too. Because I think that when my array retain their indexes even deleting I would be able to solve this problem. But still can't.
Hope you understand my question.
Is there a way to make my array or my iCarousel.view not adjust their indexes when Im deleting. To still retain my indexes the right way. Or are there other solution like adjusting my array, the same as adjusting my PhotoViewController picked indexes too. Because I think that when my array retain their indexes even deleting I would be able to solve this problem. But still can't.
The only way you have to modify the way iCarousel manages its indexes is by modifying the code. Indeed, if you look at the removeViewAtIndex method in iCarousel.m, you will see that indexes are managed through an NSDictionary, and at the moment of deleting, the dictionary is rearranged (items are reordered). You could take that method:
- (void)removeViewAtIndex:(NSInteger)index
{
NSMutableDictionary *newItemViews = [NSMutableDictionary dictionaryWithCapacity:[itemViews count] - 1];
for (NSNumber *number in [self indexesForVisibleItems])
{
NSInteger i = [number integerValue];
if (i < index)
{
[newItemViews setObject:[itemViews objectForKey:number] forKey:number];
}
else if (i > index)
{
[newItemViews setObject:[itemViews objectForKey:number] forKey:[NSNumber numberWithInteger:i - 1]];
}
}
self.itemViews = newItemViews;
}
You could apply the same logic to your array, so that the carousel and your array keep in sync. Of course, if you store the indexes somewhere (slot1/slot2/slot2/slot4?), you should also update their values after removing an element.
On the other hand, I think that what you are asking here is how to do something that you believe would solve the problem you have, but you are not really explaining what the problem is. Indeed, if I understand you correctly, what you do is:
spinning the carousel;
when the carousel stops, if it is not by chance on the desired item, you "force" it to scroll to that item.
There is no reason why this should not work after deleting some elements (unless iCarousel has some bugs, then the solution would be catching the bug). The only part is knowing which index is the one you would like to move to.
As a suggestion, I would start off by simplifying your delegate carouselDidEndScrollingAnimation method. Indeed, your carouselDidEndScrollingAnimation has a parameter called carousel, well, I think this is the only carousel you should ever be referring to in that method. If you don't see it, this is the reasoning: each of your carousel will stop scrolling and the carouselDidEndScrollingAnimation will be called; so that method will be called twice. Each time that method is executed you will modify the state of both carousel1 and carousel2 (by calling scrollToItemAtIndex); therefore, on each carousel you will call scrollToItemAtIndex twice.
This does no sound very correct to me. So you should find a way to scroll only carousel1 when carouselDidEndScrollingAnimation is called for carousel1 and to scroll only carousel2 when carouselDidEndScrollingAnimation is called for carousel2.
More generally, another point I would like to raise is that the idea of:
letting a carousel stop;
scrolling it again so that it reaches the desired position;
does not seem the best implementation possible since the user would see the carousel stopping and then starting over again.
The way I would approach this is by modifying directly iCarousel implementation so that it supports this specific behavior you need.
Concretely, give a look at the step method in iCarousel.m. This is called at each frame to produce the carousel animation. Now, in this method there is decelerating branch:
else if (decelerating)
{
CGFloat time = fminf(scrollDuration, currentTime - startTime);
CGFloat acceleration = -startVelocity/scrollDuration;
CGFloat distance = startVelocity * time + 0.5f * acceleration * powf(time, 2.0f);
scrollOffset = startOffset + distance;
[self didScroll];
if (time == (CGFloat)scrollDuration)
{
decelerating = NO;
if ([delegate respondsToSelector:#selector(carouselDidEndDecelerating:)])
{
[delegate carouselDidEndDecelerating:self];
}
if (scrollToItemBoundary || (scrollOffset - [self clampedOffset:scrollOffset]) != 0.0f)
{
if (fabsf(scrollOffset/itemWidth - self.currentItemIndex) < 0.01f)
{
//call scroll to trigger events for legacy support reasons
//even though technically we don't need to scroll at all
[self scrollToItemAtIndex:self.currentItemIndex duration:0.01];
}
else
{
[self scrollToItemAtIndex:self.currentItemIndex animated:YES];
}
}
else
{
CGFloat difference = (CGFloat)self.currentItemIndex - scrollOffset/itemWidth;
if (difference > 0.5)
{
difference = difference - 1.0f;
}
else if (difference < -0.5)
{
difference = 1.0 + difference;
}
toggleTime = currentTime - MAX_TOGGLE_DURATION * fabsf(difference);
toggle = fmaxf(-1.0f, fminf(1.0f, -difference));
}
}
}
and you see that when the carousel stops decelerating, it is scrolled again. This is exactly the same as you are doing, so you might find a way to modify this code and have the carousel scrolls exactly to the index you need. In this way you would get a far smoother spinning of the carousel.
Hope this helps and apologies for the lengthy reply.
Its a little difficult to know what the issue is here. Are you using a single NSMutableArray for the images and using the NSUserDefaults value to get the object at the index in the array?
Im not 100% sure on what is happening. What does the user do(and in what view) and what is triggered after that(which view is presented).
Are you trying to stop the "spinning" images on the image that is the same as the one picked from the previous view?
According to your images above, the images are off by a single index. Is this the case every time? Maybe there is an issue with your fetching from the array.
If you give me some more info I can help.
I looked through the code you pasted again and I think this might be your issue
if (twoSlot1 > [(UIImageView*)[self.carousel2 currentItemView] tag]){
[self.carousel1 scrollToItemAtIndex:(-twoSlot1)-2 duration: 3.5f];
} else {
[self.carousel1 scrollToItemAtIndex:-twoSlot1 duration: 3.5f];
}
On all other code blocks like that you have this where you call each carousel. In the above code you call carousel 1 twice.
if (slot2 > [(UIImageView*)[self.carousel1 currentItemView] tag]){
[self.carousel1 scrollToItemAtIndex:(-slot2)-2 duration: 3.0f];
} else {
[self.carousel1 scrollToItemAtIndex:-slot2 duration: 3.0f];
}
if (twoSlot2 > [(UIImageView*)[self.carousel2 currentItemView] tag]){
[self.carousel2 scrollToItemAtIndex:(-twoSlot2)-2 duration: 3.5f];
} else {
[self.carousel2 scrollToItemAtIndex:-twoSlot2 duration: 3.5f];
}
You call self.carousel1 when you should be calling number 2.
Is this correct?
Referring to your question. You want an array that does not change its members' indexes when a member is deleted from the array.
I guess you could use an NSMutableDictionary. It is an associative array so to say, where the indexes are of your choice and they remain unchanged when you delete a member from in between.
You may still use 0..n as your Index. You can still use some methods that you are familiar with from NSArray, such as count. You can use an enumerator to go through all members of the dictionary. On the other hand you can still use your for-loops as you are used to use them with arrays. Just be prepared that a) objectForKey:i may return nil if the key/index does not exist (e.g. was deleted) and that count retuns the number of the objects but not the highest index+1 as it does with arrays.
Not sure if I understand completely, but when one of the elements in your mutable array is deleted, rather than just deleting it, maybe insert it with another "dummy" place holder object? That way your indexes won't change at all when a delete occurs
I'm having a hard time understanding your overall problem, but from what I can gather the crux of your question is this:
Is there a way to make my array or my iCarousel.view not adjust their indexes when Im deleting.
I don't know whether it will solve your bigger issue, but using an NSMutableDictionary to simulate an array should allow you to do this. You can simply use the indices as the keys to the dictionary, and then when you remove the item associated with an index, no other indices will be adjusted as a result. For example:
NSMutableDictionary *arrayDict = [[NSMutableDictionary alloc] init];
[arrayDict setValue:foo forKey:[NSNumber numberWithInt:[arrayDict count]]];
[arrayDict setValue:bar forKey:[NSNumber numberWithInt:[arrayDict count]]];
[arrayDict setValue:fooBar forKey:[NSNumber numberWithInt:[arrayDict count]]];
And then you can access the object an at index with [arrayDict objectForKey:[NSNumber numberWithInt:index]].
Note that using an NSNumber for the key parameter of setValue:forKey: will generate a warning, but you can safely ignore this (or use the string representation if it bothers you).

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];

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.