How do iOS animation blocks work? - ios

In iOS, you can animate view objects using animation blocks:
[UIView animateWithDuration:1.0 animations:^{
firstView.alpha = 0.0;
secondView.alpha = 1.0;
}];
What we have here is a code block that describes what the view properties will end up looking after the animation is finished.
How does this work?
I could understand (I think) if this was done using some declarative format, but from the looks of it, the animation block is just a regular piece of code that presumably has to be executed, the results inspected and then someone transcoded into the actual lower-level graphics code that performs the animation.
Is the block actually executed (or somehow reverse-engineered) and if so, when?
If this code is executed before the animation starts, then how come the changes to the referenced view properties are not reflected immediately?
What happens if I put code in the block that does not change view properties, but does something else?

Yes, the block is actually invoked -- then it changes the view's properties immediately. The UIView's property setters are responsible to see if the set was used within an animation context -- if so, they calculate the animation frames etc. using CoreAnimation and CoreGraphics.
If you put non-animation code into these blocks, nothing special will happen -- the block will be executed immediately.

It is instructive to look at the equivalent code prior to blocks:
[UIView beginAnimations:#"foo" context:NULL];
[UIView setAnimationDuration:1.0];
firstView.alpha = 0.0;
secondView.alpha = 1.0;
[UIView commitAnimations];
So you see, even before blocks, the properties to change are also set directly; however, they do not take effect immediately (they are animated).
How does it work? Presumably when you set a property on the view, it checks to see if you're run beginAnimations but not commitAnimations, and does not take effect immediately if it is (but rather adds it to the list of things to animate for that animation).
So what the blocks version does is very simple in the context of the pre-blocks version: you can just think of it as running the animation block inside beginAnimations and commitAnimations lines.

Apple doesn't really talk about the nitty-gritty details of how it works, but here's what I think happens:
The system adds KVO observers on all the animatable properties of a view when the view is added to the view hierarchy.
When your animation block executes, the system sets a state that watches for KVO notifications on those properties. The code that gets invoked then creates and adds the appropriate CAAnimation objects to each affected view's layer.

Related

how is UIView. Animate (withduration:) implemented? [duplicate]

Ever since their introduction in iOS 4, I have been wondering about the internal implementation of the UIView's block-based animation methods. In particular I would like to understand what mystical features of Objective C are used there to capture all the relevant layer state changes before and after execution of the animation block.
Observing the black-box implementation, I gather that it needs to capture the before-state of all layer properties modified in the animation block, to create all the relevant CAAnimations. I guess it does not do a snapshot of whole view hierarchy, as that would be horribly inefficient. The animation block is opaque code blob during runtime, so I don't think it can analyze that directly. Does it replace the implementation of property setters on CALayer with some kind of recoding versions? Or is the support for this property change recoding baked-in somewhere deep inside the CALayers?
To generalize the question a little bit, is it possible do create similar block-based API for recording state changes using some Objective C dark magic, or does this rely on knowing and having the access to the internals of the objects being changed in the block?
It is actually a very elegant solution that is built around the fact that the view is the layers delegate and that stand-alone layers implicitly do animate on property changes.
It just happens to be that I gave a BLITZ talk about this at NSConference just a couple of days ago and I posted my slides on GitHub and tried to write down more or less what I said in the presenter notes.
That said: it is a very interesting question that I don't see being asked very often. It may be a bit to broad but I really like curiosity.
UIView animations existed before iOS 4
Ever since their introduction in iOS 4, I have been wondering about the internal implementation of the UIView's block-based animation methods.
UIView animations existed before iOS 4 but in a different style (that is no longer recommended to use because it is more cumbersome to use). For example, animating position and color of a view with a delay could be done like this. Disclaimer: I did not run this code so it may contains bugs.
// Setup
static void *myAnimationContext = &myAnimationContext;
[UIView beginAnimations:#"My Animation ID" context:myAnimationContext];
// Configure
[UIView setAnimationDuration:1.0];
[UIView setAnimationDelay:0.25];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
// Make changes
myView.center = newCenter;
myView.backgroundColor = newColor;
// Commit
[UIView commitAnimations];
The view-layer synergy is very elegant
In particular I would like to understand what mystical features of Objective C are used there to capture all the relevant layer state changes before and after execution of the animation block.
It is actually the other way around. The view is built on top of the layer and they work together very closely. When you set a property on the view it sets the corresponding property on the layer. You can for example see that the view doesn't even have it's own variable for the frame, bounds or position.
Observing the black-box implementation, I gather that it needs to capture the before-state of all layer properties modified in the animation block, to create all the relevant CAAnimations.
It does not need to do that and this is where it all gets very elegant. Whenever a layer property changes, the layer looks for the action (a more general term for an animation) to execute. Since setting most properties on a view actually sets the property on the layer, you are implicitly setting a bunch of layer properties.
The first place that the layer goes looking for an action is that it asks the layer delegate (it is documented behaviour that the view is the layers delegate). This means that when the layer property changes, the layers asks the view to provide an animation object for that each property change. So the view doesn't need to keep track of any state since the layer has the state and the layer asks the view to provide an animation when the properties change.
Actually, that's not entirely true. The view needs to keep track of some state such as: if you are inside of the block or not, what duration to use for the animation, etc.
You could imagine that the API looks something like this.
Note: I don't know what the actual implementation does and this is obviously a huge simplification to prove a point
// static variables since this is a class method
static NSTimeInterval _durationToUseWhenAsked;
static BOOL _isInsideAnimationBlock;
// Oversimplified example implementation of how it _could_ be done
+ (void)animateWithDuration:(NSTimeInterval)duration
animations:(void (^)(void))animations
{
_durationToUseWhenAsked = duration;
_isInsideAnimationBlock = YES;
animations();
_isInsideAnimationBlock = NO;
}
// Running the animations block is going to change a bunch of properties
// which result in the delegate method being called for each property change
- (id<CAAction>)actionForLayer:(CALayer *)layer
forKey:(NSString *)event
{
// Don't animate outside of an animation block
if (!_isInsideAnimationBlock)
return (id)[NSNull null]; // return NSNull to don't animate
// Only animate certain properties
if (![[[self class] arrayOfPropertiesThatSupportAnimations] containsObject:event])
return (id)[NSNull null]; // return NSNull to don't animate
CABasicAnimation *theAnimation = [CABasicAnimation animationWithKeyPath:event];
theAnimation.duration = _durationToUseWhenAsked;
// Get the value that is currently seen on screen
id oldValue = [[layer presentationLayer] valueForKeyPath:event];
theAnimation.fromValue = oldValue;
// Only setting the from value means animating form that value to the model value
return theAnimation;
}
Does it replace the implementation of property setters on CALayer with some kind of recoding versions?
No (see above)
Or is the support for this property change recoding baked-in somewhere deep inside the CALayers?
Yes, sort of (see above)
Creating similar API yourself
To generalize the question a little bit, is it possible do create similar block-based API for recording state changes using some Objective C dark magic, or does this rely on knowing and having the access to the internals of the objects being changed in the block?
You can definitely create a similar block based API if you want to provide your own animations based on property changes. If you look at the techniques I showed in my talk at NSConference for inspecting UIView animations (directly asking the layer for the actionForLayer:forKey: and using layerClass to create a layer that logs all addAnimation:forKey: information) then you should be able to learn enough about how the view is using the layer to create this abstraction.
I'm not sure if recording state changes is you end goal or not. If you only want to do your own animation API then you shouldn't have to. If you really want to do it, You could probably could, but there wouldn't be as much communication infrastructure (delegate methods and callbacks between the view and the layer) available to you as there is for animations.
David's answer is awesome. You should accept it as the definitive answer.
I do have a minor contribution. I created a markdown file in one of my github projects called "Sleuthing UIView Animations." (link) It goes into more detail on how you can watch the CAAnimation objects that the system creates in response to UIView animations. The project is called KeyframeViewAnimations. (link)
It also shows working code that logs the CAAnimations that are created when you submit UIView animations.
And, to give credit where credit is due, it was David who suggested the technique I use.

Understanding ios UIView animation block and dispatch_async(dispatch_get_main_queue) block

I am trying to get a better understanding of this topic. Lets say I want to do some really cool animation like the following
- (void)coolAnimation
{
[UIView animateWithDuration: some duration
animations:^{ some animation }];
}
Since its an animation block, does it automatically added to the main_queue ? Or for best practice, I should always add the UI updates into the main_queue like the following.
dispatch_async(dispatch_get_main_queue(), ^{
[self coolAnimation];
});
The contents of your block are performed on the main thread regardless of where you call [UIView animateWithDuration:animations:]. It's best to let the OS run your animations; the animation thread does not block the main thread -- only the animation block itself.
In a very high-level hand-wavy kind of view of this, [UIView animateWithDuration:animations:] evaluates your block and determines functions for each animatable value within it. The OS has an animation thread that it uses as its frame timer, then at each tick it sends an update on the main thread to your animatable properties with their progressing values. (You can check the current state of these values on your presentationLayer.)
The animation block you pass is called immediately. No need to use any queues.

Internal implementation of UIView's block-based animation methods

Ever since their introduction in iOS 4, I have been wondering about the internal implementation of the UIView's block-based animation methods. In particular I would like to understand what mystical features of Objective C are used there to capture all the relevant layer state changes before and after execution of the animation block.
Observing the black-box implementation, I gather that it needs to capture the before-state of all layer properties modified in the animation block, to create all the relevant CAAnimations. I guess it does not do a snapshot of whole view hierarchy, as that would be horribly inefficient. The animation block is opaque code blob during runtime, so I don't think it can analyze that directly. Does it replace the implementation of property setters on CALayer with some kind of recoding versions? Or is the support for this property change recoding baked-in somewhere deep inside the CALayers?
To generalize the question a little bit, is it possible do create similar block-based API for recording state changes using some Objective C dark magic, or does this rely on knowing and having the access to the internals of the objects being changed in the block?
It is actually a very elegant solution that is built around the fact that the view is the layers delegate and that stand-alone layers implicitly do animate on property changes.
It just happens to be that I gave a BLITZ talk about this at NSConference just a couple of days ago and I posted my slides on GitHub and tried to write down more or less what I said in the presenter notes.
That said: it is a very interesting question that I don't see being asked very often. It may be a bit to broad but I really like curiosity.
UIView animations existed before iOS 4
Ever since their introduction in iOS 4, I have been wondering about the internal implementation of the UIView's block-based animation methods.
UIView animations existed before iOS 4 but in a different style (that is no longer recommended to use because it is more cumbersome to use). For example, animating position and color of a view with a delay could be done like this. Disclaimer: I did not run this code so it may contains bugs.
// Setup
static void *myAnimationContext = &myAnimationContext;
[UIView beginAnimations:#"My Animation ID" context:myAnimationContext];
// Configure
[UIView setAnimationDuration:1.0];
[UIView setAnimationDelay:0.25];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
// Make changes
myView.center = newCenter;
myView.backgroundColor = newColor;
// Commit
[UIView commitAnimations];
The view-layer synergy is very elegant
In particular I would like to understand what mystical features of Objective C are used there to capture all the relevant layer state changes before and after execution of the animation block.
It is actually the other way around. The view is built on top of the layer and they work together very closely. When you set a property on the view it sets the corresponding property on the layer. You can for example see that the view doesn't even have it's own variable for the frame, bounds or position.
Observing the black-box implementation, I gather that it needs to capture the before-state of all layer properties modified in the animation block, to create all the relevant CAAnimations.
It does not need to do that and this is where it all gets very elegant. Whenever a layer property changes, the layer looks for the action (a more general term for an animation) to execute. Since setting most properties on a view actually sets the property on the layer, you are implicitly setting a bunch of layer properties.
The first place that the layer goes looking for an action is that it asks the layer delegate (it is documented behaviour that the view is the layers delegate). This means that when the layer property changes, the layers asks the view to provide an animation object for that each property change. So the view doesn't need to keep track of any state since the layer has the state and the layer asks the view to provide an animation when the properties change.
Actually, that's not entirely true. The view needs to keep track of some state such as: if you are inside of the block or not, what duration to use for the animation, etc.
You could imagine that the API looks something like this.
Note: I don't know what the actual implementation does and this is obviously a huge simplification to prove a point
// static variables since this is a class method
static NSTimeInterval _durationToUseWhenAsked;
static BOOL _isInsideAnimationBlock;
// Oversimplified example implementation of how it _could_ be done
+ (void)animateWithDuration:(NSTimeInterval)duration
animations:(void (^)(void))animations
{
_durationToUseWhenAsked = duration;
_isInsideAnimationBlock = YES;
animations();
_isInsideAnimationBlock = NO;
}
// Running the animations block is going to change a bunch of properties
// which result in the delegate method being called for each property change
- (id<CAAction>)actionForLayer:(CALayer *)layer
forKey:(NSString *)event
{
// Don't animate outside of an animation block
if (!_isInsideAnimationBlock)
return (id)[NSNull null]; // return NSNull to don't animate
// Only animate certain properties
if (![[[self class] arrayOfPropertiesThatSupportAnimations] containsObject:event])
return (id)[NSNull null]; // return NSNull to don't animate
CABasicAnimation *theAnimation = [CABasicAnimation animationWithKeyPath:event];
theAnimation.duration = _durationToUseWhenAsked;
// Get the value that is currently seen on screen
id oldValue = [[layer presentationLayer] valueForKeyPath:event];
theAnimation.fromValue = oldValue;
// Only setting the from value means animating form that value to the model value
return theAnimation;
}
Does it replace the implementation of property setters on CALayer with some kind of recoding versions?
No (see above)
Or is the support for this property change recoding baked-in somewhere deep inside the CALayers?
Yes, sort of (see above)
Creating similar API yourself
To generalize the question a little bit, is it possible do create similar block-based API for recording state changes using some Objective C dark magic, or does this rely on knowing and having the access to the internals of the objects being changed in the block?
You can definitely create a similar block based API if you want to provide your own animations based on property changes. If you look at the techniques I showed in my talk at NSConference for inspecting UIView animations (directly asking the layer for the actionForLayer:forKey: and using layerClass to create a layer that logs all addAnimation:forKey: information) then you should be able to learn enough about how the view is using the layer to create this abstraction.
I'm not sure if recording state changes is you end goal or not. If you only want to do your own animation API then you shouldn't have to. If you really want to do it, You could probably could, but there wouldn't be as much communication infrastructure (delegate methods and callbacks between the view and the layer) available to you as there is for animations.
David's answer is awesome. You should accept it as the definitive answer.
I do have a minor contribution. I created a markdown file in one of my github projects called "Sleuthing UIView Animations." (link) It goes into more detail on how you can watch the CAAnimation objects that the system creates in response to UIView animations. The project is called KeyframeViewAnimations. (link)
It also shows working code that logs the CAAnimations that are created when you submit UIView animations.
And, to give credit where credit is due, it was David who suggested the technique I use.

How can animation be unit tested?

Modern user interfaces, especially MacOS and iOS, have lots of “casual” animation -- views that appear through brief animated sequences largely orchestrated by the system.
[[myNewView animator] setFrame: rect]
Occasionally, we might have a slightly more elaborate animation, something with an animation group and a completion block.
Now, I can imagine bug reports like this:
Hey -- that nice animation when myNewView appears isn't happening in the new release!
So, we'd want unit tests to do some simple things:
confirm that the animation happens
check the duration of the animation
check the frame rate of the animation
But of course all these tests have to be simple to write and mustn't make the code worse; we don’t want to spoil the simplicity of the implicit animations with a ton of test-driven complexity!
So, what is a TDD-friendly approach to implementing tests for casual animations?
Justifications for unit testing
Let's take a concrete example to illustrate why we'd want a unit test. Let's say we have a view that contains a bunch of WidgetViews. When the user makes a new Widget by double-clicking, it’s supposed to initially appear tiny and transparent, expanding to full size during the animation.
Now, it's true that we don't want to need to unit test system behavior. But here are some things that might go wrong because we fouled things up:
The animation is called on the wrong thread, and doesn't get drawn. But in the course of the animation, we call setNeedsDisplay, so eventually the widget gets drawn.
We're recycling disused widgets from a pool of discarded WidgetControllers. NEW WidgetViews are initially transparent, but some views in the recycle pool are still opaque. So the fade doesn't happen.
Some additional animation starts on the new widget before the animation finishes. As a result, the widget begins to appear, and then starts jerking and flashing briefly before it settles down.
You made a change to the widget's drawRect: method, and the new drawRect is slow. The old animation was fine, but now it's a mess.
All of these are going to show up in your support log as, "The create-widget animation isn't working anymore." And my experience has been that, once you get used to an animation, it’s really hard for the developer to notice right away that an unrelated change has broken the animation. That's a recipe for unit testing, right?
The animation is called on the wrong thread, and doesn't get drawn.
But in the course of the animation, we call setNeedsDisplay, so
eventually the widget gets drawn.
Don't unit test for this directly. Instead use assertions and/or raise exceptions when animation is on the incorrect thread. Unit test that the assertion will raise an exception appropriately. Apple does this aggressively with their frameworks. It keeps you from shooting yourself in the foot. And you will know immediately when you are using an object outside of valid parameters.
We're recycling disused widgets from a pool of discarded
WidgetControllers. NEW WidgetViews are initially transparent, but some
views in the recycle pool are still opaque. So the fade doesn't
happen.
This is why you see methods like dequeueReusableCellWithIdentifier in UITableView. You need a public method to get the reused WidgetView which is the perfectly opportunity to test properties like alpha are reset appropriately.
Some additional animation starts on the new widget before the
animation finishes. As a result, the widget begins to appear, and then
starts jerking and flashing briefly before it settles down.
Same as number 1. Use assertions to impose your rules on your code. Unit test that the assertions can be triggered.
You made a change to the widget's drawRect: method, and the new
drawRect is slow. The old animation was fine, but now it's a mess.
A unit test can be just timing a method. I often do this with calculations to ensure they stay within a reasonable time limit.
-(void)testAnimationTime
{
NSDate * start = [NSDate date];
NSView * view = [[NSView alloc]init];
for (int i = 0; i < 10; i++)
{
[view display];
}
NSTimeInterval timeSpent = [start timeIntervalSinceNow] * -1.0;
if (timeSpent > 1.5)
{
STFail(#"View took %f seconds to calculate 10 times", timeSpent);
}
}
I can read your question two ways, so I want to separate those.
If you are asking, "How can I unit test that the system actually performs the animation that I request?", I would say it's not worth it. My experience tells me it is a lot of pain with not a lot of gain and in this kind of case, the test would be brittle. I've found that in most cases where we call operating system APIs, it provides the most value to assume that they work and will continue to work until proven otherwise.
If you are asking, "How can I unit test that my code requests the correct animation?", then that's more interesting. You'll want a framework for test doubles like OCMock. Or you can use Kiwi, which is my favorite testing framework and has stubbing and mocking built in.
With Kiwi, you can do something like the following, for example:
id fakeView = [NSView nullMock];
id fakeAnimator = [NSView nullMock];
[fakeView stub:#selector(animator) andReturn:fakeAnimator];
CGRect newFrame = {.origin = {2,2}, .size = {11,44}};
[[[fakeAnimator should] receive] setFrame:theValue(newFrame)];
[myController enterWasClicked:nil];
You don't want to actually wait for the animation; that would take the time the animation takes to run. If you have a few thousand tests, this can add up.
More effective is to mock out the UIView static method in a category so that it takes effect immediately. Then include that file in your test target (but not your app target) so that the category is compiled into your tests only. We use:
#import "UIView+SpecFlywheel.h"
#implementation UIView (SpecFlywheel)
#pragma mark - Animation
+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion {
if (animations)
animations();
if (completion)
completion(YES);
}
#end
The above simply executes the animation block immediately, and the completion block immediately if it's provided as well.

How can I handle sequential animations cleanly within an MVC design?

I've written some code that moves some objects around on the screen in sequence. As each object finishes moving, the next starts.
The code is structured similarly to this:
Model:
moveObject
{
// Code to move the object
...
[delegate moved:self];
}
Delegate (Controller):
moved:(MyClass *)o
{
UIView* v = [self viewForObject:o];
[UIView animateWithDuration:1.0
animations:^{
[v setCenter: [model center]];
}
completion:^(BOOL finished){
// Move object
[model moveObject];
}];
}
Aside from the fact that this doesn't actually work correctly, it doesn't seem conceptually right to me. The logic in the model should be free to carry on moving things around without having to wait to be nudged by the controller telling it that the views are ready for more updates.
My plan is to create a queue of pending actions-requiring-animation, and each time the model updates something which needs animating, just add it to the queue and let it carry on. Then I could pluck actions off the queue and animate them one at a time.
This would also mean that I could use the model without any views at all, without having to write a separate controller that just keeps calling back into the model when objects are moved.
So before I start working on my own solution for this, is there already code to handle this in Apple's APIs? It seems like it would be a common enough problem that there would be a standard method of handling it.
Alternatively, is there a better way to handle building chains of animations at run-time? (As opposed to simply hard coding them using the completion block.)

Resources