Are multiple UIView animation callbacks a bad idea (i.e. cause mem issues)? - iphone

I have multiple UIView animations running in my app. They are very short, and then make callbacks to a method that then usually fires off another animation. This leads to a lot of little animations running at the same time, each firing back callbacks.
This actually performs pretty well, and for the first few levels (the app is a game), no problems are observed. However, as you continue to play deeper into the game, I'm starting to get memory warnings and ultimately crashes. I've put NSLog in all of my dealloc methods, so I can see that everything is being properly released and dealloc'd. I've also run static analysis on the app and fixed anything it found.
The weird part to me is this: Shouldn't any performance problems caused by running multiple animations be processor bound (i.e. shouldn't I see a bunch of slowdown and such)? It seems that everything performs just fine, it just runs up memory too fast and there's nothing more I can free. Is there something in the framework on the UIView side of things that will need lots of memory to do these operations? Is there perhaps a leak in the framework I need to avoid when doing these?
Additional note: I'm animating a custom class that extends UIView and has a label and a UIImageView inside of them.

Multiple animation shouldn't cause memory warnings..
I suggest you should run Instruments for Leaks, ObjectAlloc & CPU Samplers..
That would give a much better view than NSLogs in dealloc

You don't show any code so it's hard to give specific advice, however, have you considered using Core Animation layers instead of UIViews? If you need to animate text, you'll have to use a view since there is no CATextLayer on the phone, however, Core Animation provides the facilities to draw complex sprites in a 2d space making it a great candidate for many games.
Best Regards.

Related

cocos2d using gobs of memory

I'm having the absolute worst time with running out of memory in my game with cocos2d.
I have 4 scenes. two vanish from memory when I switch scenes using
[[CCDirector sharedDirector]replaceScene:sceneWithTransition]
I've tried push/pop and it makes the problem about 10x worse.
2 of the scenes however are like a virus. The conditions under which I can remove them from memory do not exist.
I am using the ARC alterations. I was hoping they would help, they did not.
I've overridden the cleanup method to make sure I get rid of references to everything in the scenes. The first one is the game play scene, and I can imagine how it might be possible that I've missed something that is somehow holding on to the scene. However the other one is the settings scene. It has 5 parts. they all get tossed and yet the scene will not purge. before converting to ARC the app was unusable it crashed so often and when it wasn't crashing it was running out of memory. After ARC it lasts about 4x longer than before but still runs out of memory regularly. Crashes however are almost non-existant.
I suppose first off, what is the correct way to switch between scenes?
Second, how does one remove something from memory when using arch because object = nil does nothing. All of my other programs using ARC run like dreams. None of them use the cocos2d engine. I'd not seen a memory error since the introduction of arc until I made the mistake of converting my quartz2d game in to cocos2d. The only reason I don't o back to a platform that actually functions is that I really like the effects possible in cocos that I simply cannot make work in quartz.
It seems that cocos2d had some issues with ARC that got fixed only recently.
I don't know if this has to do with your memory problems, but you might check which cocos2d version you are using.
Anyway, it seems that cocos2d will fully support ARC only from version 2.0. So, you might be better off not using ARC and getting your memory management right by properly using release. As far as I know, cocos2d has no memory problem, so you should be able to accomplish it.
push/pop from what I understand use a "stack" model thus memory is not erased when new scenes are pushed or popped, which would explain why that gets worse when using this method.
one way you can help save memory, especially during a transition, is to transition to a loading scene and then from there transition to the actual scene you want. This is because during a normal transition, both scenes occupy memory simultaneously for at least 1 frame, whereas a cheap loading scene will instead take each of their places, reducing the horrible memory spike that often occurs when transitioning between two intense scenes.

iOS frame-by-frame animation with Quartz

I'm working on an iPhone game that involves only two dimensional, translation-based animation of just one object. This object is subclassed from UIView and drawn with Quartz-2D. The translation is currently put into effect by an NSTimer that ticks each frame and tells the UIView to change its location.
However, there is some fairly complex math that goes behind determining where the UIView should move during the next frame. Testing the game on the iOS simulator works fine, but when testing on an iPhone it definitely seems to be skipping frames.
My question is this: is my method of translating the view frame by frame simply a bad method? I know OpenGL is more typically used for games, but it seems a shame to set up OpenGL for such a simple animation. Nonetheless, is it worth the hassle?
It's hard to say without knowing what kind of complex math is going on to calculate the translations. Using OpenGL for this only makes sense if the GPU is really the bottleneck. I would suspect that this is not the case, but you have to test which parts are causing the skipped frames.
Generally, UIView and CALayer are implemented on top of OpenGL, so animating the translation of a UIView already makes use of the GPU.
As an aside, using CADisplayLink instead of NSTimer would probably be better for a game loop.
The problem with the iPhone simulator is it has access to the same resources as your mac. Your macs ram, video card etc. What I would suggest doing is opening instruments.app that comes with the iPhone SDK, and using the CoreAnimation template to have a look at how your resources are being managed. You could also look at allocations to see if its something hogging ram. CPU could also help.
tl;dr iPhone sim uses your macs ram and GFX card. Try looking at the sequence in Instruments to see if theres some lag.

Does it help to start intensive core animation blocks in another thread?

I have an scroll view with some sophisticated animations happening during scrolling. Although after 2 weeks of finetuning the performance is acceptable now, the scrolling is not 100% smooth when the animations happen.
I know that core animation does animations in a background thread. But I wonder if it would help to split those animation blocks (10 of them at pretty much the same time) into threads.
There are a few methods that look interesting:
– performSelector:onThread:withObject:waitUntilDone:
– performSelectorInBackground:withObject:
or is that nonsense to do?
No, it won't help. As you correctly stated yourself, Core Animation already runs in a seperate thread. Core Animation is smart enough to handle animation blocks as efficiently as possible. I wouldn't advise interfering with it.
The Core Animation Programming Guide says:
An abstract animation interface that
allows animations to run on a separate
thread, independent of your
application's run loop. Once an
animation is configured and starts,
Core Animation assumes full
responsibility for running it at frame
rate.
Are you sure the choppy behavior is really from CA? Do you have anything else going on?
If you have any background network access, consider moving that into a separate thread - the time taken to service those calls takes away from time the UI spends updating the screen as you scroll.

How can I programmatically determine CPU usage rate or how busy / occupied the system is in iPhone-OS?

My app is doing some pretty but heavy weight core animations during scrolling. Sometimes it crashes due to bad performance. So I need some way to find out if there is enough capability to make the animations, and if not, I just leave them away. Best way would be if I could ask the system how busy it is.
UPDATE: I mean especially Core Animation.
By animation, do you mean frames that play after one another (like an animated GIF) or some CoreAnimation (OpenGL) effect that is moving polygons with mapped textures around?
If it's the former, I'd really consider some way of optimizing the animation or eliminating it in all cases.
If it's the latter, I'd do some deeper digging into the source of the problem. Core Animation under normal circumstances will drop frames in order to keep from getting into situations like this in the first place.
In either case case you might consider loading the texture assets a little earlier. I have had some trouble in my apps with animation methods that take a UIImage parameter when I created the UIImage in the function call. Preloading the asset a little earlier in my code took care of the problem nicely.
As an example:
BAD
[[UIImage imageNamed:#"checkmark.png"] drawAtPoint:p];
BETTER
//declared at top of class
static UIImage *checkmark = nil;
in init:
checkmark = [UIImage imageNamed:#"checkmark.png"];
in drawRect:
[checkmark drawAtPoint:p];
You would need to adapt this technique to your particular situation. In my case, checkmark is used often, and it quite small, I don't mind dedicating the memory to it permanently.
I wonder if your crashes could be fixed by making sure the assets were ready to be used by the application.
I wouldn't do that. If your app crashes, it's to heavy. You could run your app with some instruments to see where your bottlenecks are.
So, without trying to sound too harsh, your best way is to rewrite some parts in order to make you app run on an iPhone at all times.

Delay with touch events

We have an app in AppStore Bust~A~Spook we had an issue with. When you tap the screen we use CALayer to find the position of all the views during their animation and if you hit one we start a die sequence. However, there is a noticeable delay, it appears as if the touches are buffered and we we receive the event to late. Is there a way to poll or any better way to respond to touches to avoid this lag time?
This is in a UIView not a UIScrollView
Are you using a UIScrollView to host all this? There's a property of that called delaysContentTouches. This defaults to YES, which means the view tries to ascertain whether a touch is a scroll gesture or not, before passing it on. You might try setting this to NO and seeing if that helps.
This is a pretty old post about a seasonal app, so the OP probably isn't still working on this problem, but in case others come across this same problem and find this useful.
I agree with Kriem that CPU overload is a common cause of significant delay in touch processing, though there is a lot of optimization one can do before having to pull out OpenGL. CALayer is quite well optimized for the kinds of problems you're describing here.
We should first check the basics:
CALayers added to the main view's layer
touchesBegan:withEvent: implemented in the main view
When the phase is UITouchPhaseBegan, you call hitTest: on the main view's layer to find the appropriate sub-layer
Die sequence starts on the relevant model object, updating the layer.
Then, we can check performance using Instruments. Make sure your CPU isn't overloaded. Does everything run fine in simulator but have trouble on the device?
The problem you're trying to solve is very common, so you should not expect a complex or tricky solution to be required. It is most likely that the design or implementation has a basic flaw and just needs troubleshooting.
Delayed touches usually indicates a CPU overload. Using a NSTimer for frame-to-frame based action is prone to interfering with the touch handling.
If that's the case for your app, then my advice is very simple: OpenGL.
If you're doing any sort of core-animation animation of the CALayers at the same time as you're hit-testing, you must get the presentationLayer before calling hitTest:, as the positions of the model layers do not reflect what might be on screen, but the positions to which the layers are animating.
Hope that helps.