UIView Animations with Objective-C Blocks - iphone

I have been playing around with the two different ways of doing UIView animations: begin/commit and Blocks.
I have noticed that the beginAnimations:context: / commitAnimations way of doing things is nicely asynchronous, keeping the UI free while the animation is running.
However, I also noticed that the animateWithDuration:animations:completion way seems to block the UI, making it unresponsive while the animation is running.
I thought one of the main points of using blocks was to achieve asynchronous execution easily. Why does the blocks variant of the UIView animarions block the UI while the begin/commit variant does not?
Edit:
My question originally assumed that the blocks animation was a synchronous operation and blocked the UI. As it transpired from Jeff Kelly's answer, that this isn't the case. My original assumption was incorrect, the blocks animation is not synchronous. See Jeff's answer for the details.

Are you using the right UIView class method? If you use +animateWithDuration:delay:options:animations:completion:, you can specify a bitmask of options. One of the possible options is UIViewAnimationOptionAllowUserInteraction, which sounds like just what you want.

Related

Blocking on UIImageView animation, or, "while not finished animating, spin"

I'm currently animating many images via 4 UIImageViews, and all is well on that front. The animations complete as expected, and I am assuming that they run inside their own NSThread, as execution continues despite the animation. Of course, this is good and expected behaviour, as I definitely wouldn't want my whole app to halt until the animation finishes.
However, I need to kick off a method which needs to depend on whether the animation is running or not.
The following code is bad as I understand, as introducing loops and other delays inside the main thread causes instability.
while([self.fooImgView isAnimating])
;
This code effectively halts execution of the whole app. I need to find a way to "spin" until the animation completes, without wedging the app.
Any advice on this would be greatly appreciated.
Thanks!
sc.
If you use block animations like this one, you can use the completion block to call some delegate or execute your method

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

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.

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.

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.

Using Core Graphics/ Cocoa, can you draw to a bitmap context from a background thread?

I'm drawing offscreen to a CGContext created using CGBitmapContextCreate, then later generating a CGImage from it with CGBitmapContextCreateImage and drawing that onto my view in drawRect (I'm also drawing some other stuff on top of that - this is an exercise in isolating different levels of variability and complexity).
This all works fine when it's all running on the main thread. However one of the motivations for splitting this out this way was so that the offscreen part could be run on a background thread (which I had thought should be ok since it's not rendering to an onscreen context).
However, when I do this the resulting image is empty! I've checked over the code, and placed judicious NSLog's to verify that everything is happening in the right order.
My next step is to boil this down to the simplest code that reproduces the issue (or find some silly thing I'm missing and fix it) - at which point I'd have some code to post here if necessary. But I first wanted to check here that I'm not going down the wrong path with this. I couldn't find anything in my travels around the googlesphere that sheds light either way - but a friend did mention that he ran into a similar issue while trying to resize images in a background thread - suggesting there may be some general limitation here.
[edit]
Thanks for the responses so far. If nothing else they have told me that at least I'm not alone in not having an answer for this - which was part of what I wanted to find out. At this point I'm going to put the extra work into getting the simplest possible example and may come back with some code or more information. In the meantime keep any ideas coming :-)
One point to bring up: A couple of people have used the term thread safety with respect to APIs. It should be noted that there are two types of thread safety in this context:
Threadability of the API itself - ie can it be used at all from more than one thread (global state and other re-entrancy issues such as C's strtok are common reasons that an API might not be thread safe too).
Atomicity of individual operations - can multiple threads interact with the same objects and resources through API without application level locking?
I suspect that mention so far has been of the first type, but would appreciate if you could clarify.
[edit2 - solved!]
Ok, I got it all working. Executive summary is that the problem was with me, rather than bitmap contexts themselves.
In my background thread, just before I drew into the bitmap context, I was doing some preparation on some other objects. It turns out that, indirectly, the calls to those other objects where leading to setNeedsDisplay being called on some views!
By separating the part that did that out to the main thread it now all works perfectly.
So for anyone who hits this question wondering if they can draw to a bitmap context on a background thread, the answer is you can (with the caveats that have been presented here and in the answers).
Thanks all
Just a guess, but if you are trying to call setNeedsDisplay from another thread, you need to call it via performSelectorOnMainThread instead.
What you're doing should work if you're working with the CGContextRef in one and only one thread. I've done this before with 8 cores working on 8 different parts of an image and then compositing the different resultant CGImageRefs together and drawing them onscreen.
Apple don't say anything about thread safety on iPhone but Cocoa (as opposed to UIKit) is generally thread safe for drawing. As they share a lot of drawing code, I would assume drawing on iPhone is threadsafe.
That said, your experience would imply there are problems. Could it be that you are using your image before it is rendered?
Not all APIs are thread-safe. Some require locking or require that they be run on the main thread. You may want to scour the documentation. I believe there is a page that summarizes which parts of the SDK are thread-safe and which aren't.
In case anyone is/was searching for exactly how to do this i've written a blog post that describes how to do this, and wraps the whole thing in a NSOperation subclass.