Core Animation using blocks

Previously I have written a blog post about doing simple animations with UIViews, which you can find here. Starting in iOS 4.0 you can now do this with blocks.

Blocks have two major benefits (although there are more):

The most common method that you will use to animate views using blocks, is the following class method on UIView:

+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion;

This method allows you to set a time interval, along with an animations block and a completion block.

Lets say we have a UIView variable called redView.

redView = [[UIView alloc] initWithFrame:CGRectMake(0,0,320,320)];
redView.backgroundColor = [UIColor redColor];

We will then add redView as a subview of the view controller’s view

[self.view addSubview:redView];

A common situation you may find your self in, is when you finish animating a view (e.g. changing its alpha), you would then want to remove it from it’s superview, and then release it from memory.

So if you had (for example) a method called animate to trigger off the animation, you would need to add an “animation did stop selector” to the animation. In the following example I have called it cleanUp.

- (void)animate{
   [UIView beginAnimations:@"" context:NULL];
   [UIView setAnimationDuration:5.0];
   [UIView setAnimationDidStopSelector:@selector(cleanUp)];
   [redView setAlpha:0.0];
   [UIView commitAnimations];

}

- (void)cleanUp{
    [redView removeFromSuperview];
    // I do release and = nil on the same line as a coding convention
    // so I don't forget to "nil" the variable
    [redView release], redView = nil;   
}

Although this works well enough, it does mean that your code is split up into the animation code and the (completion) clean up code. If you end up doing this a lot, your code can end up becoming very fragmented and hard to follow.

Using blocks we can do the following:

- (void)animate{

[UIView animateWithDuration:5.0

                    animations:^{ 
                              redView.alpha = 0.0; 
                         }

                   completion:^(BOOL  completed){
                              [redView removeFromSuperview];
                          [redView release],redView = nil;
                        }
 ];


}

This keeps things nice and simple, and it means that you can easily see what code will be executed when the animation completes.

All of the animations you wish to do are passed in using a block:

^{ 
redView.alpha = 0.0; 
}

This block takes no arguments, and it also does not have a return type (so it defaults to void).

Instead of calling the cleanUp selector, we can simply pass in a completion block:

^(BOOL  completed){
[redView removeFromSuperview];
[redView release],redView = nil;
}

This block takes one parameter, which is a bool signifying if the animation has completed when the block is executed. In this example we ignore the completed variable, and we assume that the animation has completed for simplicity reasons. In the body of the block we do same as we did in the cleanUp selector, we remove redView from its super view and then release it from memory.

In some situations you won’t need to use blocks for Core Animation, but when you do, you will find it cleans up your code no end.