EXC BAD ACCESS occurring when cocos2d calls ccTouchEnded in CCMenu - iphone

This only happens once in a while. When I step from a breakpoint in the method called by the menu item when pressed I end up at the end of the method and when I step out I eventually get to ccTouchEnded and then the bad access occurs. Nothing shows up in the debug output window but I get a green arrow pointing to the main method with the error message.
Any ideas why this might occur?
Thanks.

So in case anyone has the same problem, I figured out what was happening. I had a CCMenu containing several children. When a child was tapped I did what I wanted with it and then removed it from the CCMenu via removeChild:cleanup: in the method I passed as the selector for the CCMenuItem. The problem was that Cocos2d deactivates the CCMenuItem while the selector method is executed and then reactivates it when the method is finished. So in the method I was basically destroying the CCMenuItem by removing it from the CCMenu and then at the end of the method Cocos2d tried to reactivate it but it was no longer in memory.
I don't see much of a way around this, so maybe it is not possible to remove a CCMenuItem from a CCMenu in its selector method.
The way I worked around it was to simply call setVisible:NO and setIsEnabled:NO on the menuitem. However, I can imagine cases in which this would not be the best way to do it. Maybe in these cases you could mess with the z position or something to get the menuitem out of the way.
Anyway, I hope this helps someone else, I know I've been stuck on this a while. :)

A better solution, in my humble opinion, is to unwind the scene destruction call from the stack. Using something like NSTimer+BlockKit makes it really clean. Here's an excerpt from my code:
- (void)menuAction
{
// we use a timer here to delay the execution of the action because it
// destroys the current scene and we're mid a call on CCMenu's ccTouchEnded
// that isn't expecting a scene tear down
// http://stackoverflow.com/questions/11165822/exc-bad-access-occurring-when-cocos2d-calls-cctouchended-in-ccmenu
[NSTimer scheduledTimerWithTimeInterval:0 block:^(NSTimer* timer)
{
[[CCDirector sharedDirector] popSceneWithTransition:
[CCTransitionSlideInL class] duration:kTransDur];
}
repeats:NO];
}

Related

How to save data with a delay?

I'm wondering if iOS allows one to do the following:
I have a puzzle game and I've been working on saving data when the user returns to the home screen. To do this, using NSNotificationCenter, I had one of my game classes to observe [UIApplication sharedApplication]'s ApplicationWillResignActive method so when that happens I save my game state. But if the user decides to exit while animations are going on, the game will save a midState where the model values are still changing and that will often cause crashes. My question is if it is possible to somehow delay the saving process (even though it is on the background) until the animations are complete (or some variable equals 1)?
My first idea is to create scheduled event with NSTimer to try to save until everything is set. Any ideas would be appreciated. Thank you
You can use performSelector:withObject:afterDelay:
// Call doSomething after a 1 second delay
[self performSelector:#selector(doSomething) withObject:nil afterDelay:1.0f];
Rather than trying to delay the saving, especially in ApplicationWillResignActive, you should look into how to stop the animation and record the expected final values of the animation. Depending on the method of animation (UIView static methods, block based, 3rd party) there is usually a way to stop them, and since you define what the animation does you should already know the final state.
In the case of block based animations:
How to cancel UIViews block-based animation?

How to move several buttons throughout the screen

I am creating an application where I have several buttons on the screen and I want to make them move throughout the screen. User can tap on that buttons and the buttons on which user taps gets removed from the screen.Hence I have to stop the timer which moves that button.
But my main concern is How to make all the bubbles move i.e. How to manage each of them?
I have made the use of NSTimer.
NSTimer* timer = [NSTimer timerWithTimeInterval:1 target:self selector:#selector(moveTheButton) userInfo:nil repeats:YES]; [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
But this can be helpful in case if I have only one button. If there are more buttons its quite hard to manage the timers.
Also the number of buttons are dynamic.
Please suggest some alternate.
I have gone through few threads but didnt got the expected answer.
Thanks in advance for help.....
I would suggest using CAAnimations to move your buttons. This would allow you to animate your buttons smoothly without the use of NSTimers and would also be ideal for creating your button animations dynamically.
CAAnimations are created then added to a views layer. You can animate the rotation, position and size of a view using CAAnimations. It is also easy to add and remove animations from a views layer, making it ideal for dynamic content without the headache of multiple NSTimers.
How should a UIButton move? Do you mean something like randomly moving each button like in a Brownian motion? : D
Well, it really does not matter I guess, but let's consider that you have a generalized function that determines the behavior of each button given its current position, in this case you can use an NSArray to keep track of all your buttons positions at each time and just call this function over the single NSArray (then cycling through its elements) as the selector of the NSTimer.
If you do not have a single generalized function, but each button has its own, you could subclass UIButton for each kind of motion you have to take care and implement a method for each class that implements the correct motion. Then you can have a function called in NSTimer that cycles through an array of references of the buttons and calls the implemented motion method for each instance (via polymorphism)

My custom UI elements are not being updated while UIScrollView is scrolled

I have a spinning circle UI element that is updated by an NSTimer. I also have a UIScrollView that would 'block' the spinning circle while being scrolled. That was expected, because the timer and the scroll view where both in the same thread.
So I put the timer in a separate thread which basically works great! I can see it working because NSLogs keep coming even while scrolling.
But my problem is that my spinning circle is still stopping on scrolling! I suspect redrawing is halted until the next iteration of the main thread's run loop (?). So even if its angle is changed all the time, it might not be redrawn...
Any ideas what I can do? Thanks!
While scrolling, the main thread's run loop is in UITrackingRunLoopMode. So what you need to do is schedule your timer in that mode (possibly in addition to the default mode). I believe NSRunLoopCommonModes includes both the default and event tracking modes, so you can just do this:
NSTimer *timer = [NSTimer timerWithTimeInterval:0.42 target:foo selector:#selector(doSomething) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
By the way, you should do this all on the main thread. No need to spawn a background thread (unless each timer invocation is going to do some lengthy processing).
UIScrollView doesn't just block NSTimers, it blocks the entire main thread. And UIKit objects should be accessed on the main thread only (and, often, are limited in unpredictable ways if you try to dodge round that restriction), which is probably why — even if you have a clock coming in from an external thread — you're unable to post updates.
It's a bit of a dodge, but is there any way your animation can be achieved with CoreAnimation? Things tied to that continue working irrespective of what's happening in the main thread.
You are correct that UIScrollView does not update its content view during scrolling.
Probably your best bet -- and this is something of a hack -- is to display your animating view separately (perhaps within a frame-view, to get the free clipping) and use the scroll-view delegate callbacks to find out the current position of the scroll and position your animation accordingly.
NOTE: this suggestion is a hack! It's not best practices and it's certainly counter to simple, maintainable code without side effects. However, it's the only way I can think to get the display you want.
Another tack: re-think the importance of displaying animated contents of a scrolling view while it is scrolling.

Is there any seriously good reason why a view can not completely manage itself?

Example: I have an warning triangle icon, which is a UIImageView subclass. That warning is blended in with an animation, pulses for 3 seconds and then fades out.
it always has a parent view!
it's always only used this way: alloc, init, add as subview, kick off animation, when done:remove from superview.
So I want this:
[WarningIcon warningAtPosition:CGPointMake(50.0f, 100.0f) parentView:self];
BANG!
That's it. Call and forget.
The view adds itself as subview to the parent, then does it's animations. And when done, it cuts itself off from the branch with [self removeFromSupeview];. And to make sure the procedure can finish really after this, make a nifty -retain and -autorelease couple so the whole thing can complete and return before it really gets trashed.
Now some nerd a year ago told me: "Never cut yourself off from your own branch". In other words: A view should never ever remove itself from superview if it's no more referenced anywhere.
I want to get it, really. WHY? Think about this: The hard way, I would do actually the exact same thing. Create an instance and hang me in as delegate, kick off the animation, and when the warning icon is done animating, it calls me back "hey man i'm done, get rid of me!" - so my delegate method is called with an pointer to that instance, and I do the exact same thing: [thatWarningIcon removeFromSuperview]; - BANG.
Now I'd really love to know why this sucks. Life would be so easy.
I have no objections to your solution—especially with the [[self retain] autorelease]. I'm using the same approach from time to time myself.
You should go and ask the no-branch-cutter-nerd about his reasoning (and post this information here).

Timer and animation events trumping TouchesEnded events

I've implemented a tap-and-hold handler using an NSTimer that I first set in the TouchesBegan overload.
However, what I actually want is for an action to be continuously performed in quick-fire succession while the touch is being held. So, on timer expiry I call a handler to do the work, which then sets another timer and the cycle continues until the TouchesEnded comes in and cancels it, or another terminating condition is met.
This works fine, until my handler code triggers an animation to go off at the same time.
Now we have animation events and timer events going off, and in all that we need to handle TouchesEnded as well.
What I am finding is that, if the animation is triggered, and I set my timer to less than 0.025 seconds, my TouchesEnded event doesn't come through until the timer cycle stops (the other terminating condition). Setting a slower timer, or not triggering the animation, make it work (TouchedEnded comes in straight away), but are not what I want.
Obviously this is all on the device (release build - no NSLogs) - in the sim it all works fine
Is there any way of setting the relative priorty of these events - or is it likely I'm missing something else obvious here?
[Update]
I've worked around this in this instance by doing the continuous part without visual feedback until it's done (which from this users perspective is instant). I think this is ok for now. I'd still like to hear any more thoughts on this (Jeffrey's idea was good), but I'm not waiting on tenterhooks now.
Try writing your own Timer-type class by spawning off onto a thread. Example:
BOOL continue = YES; //outside of your #implementation
-(void)doLoop
{
while(continue){
[NSThread sleepForTimeInterval:.025];
[self performSelectorOnMainThread:#selector(whateverTheFunctionIs) waitUntilDone:YES];
}
}
and this would be started by [NSThread detatchNewThreadSelector:#selector(doLoop) toTarget:self withObject:nil]. This is not exactly threadsafe, but you can choose to wrap the boolean into a NSNumber and then do #synchronize on it if you so choose. Alternatively, after I wrote that little snippet I realized it would be better to do a check against the current NSTime instead of sleepForTimeInterval: but you get the point. :)