How to do 'serial' animation with GCD?

Using queues to submit animations in sequence won't work, because the method that begins the animation returns immediately, and the animation is added to the animation tree to be performed later. Each entry in your queue will complete in a tiny fraction of a second.

If each of your animations operates on the same view then by default the system should let each animation finish running before it starts the next one.

To quote the docs for the UIViewAnimationOptionBeginFromCurrentState options value:

UIViewAnimationOptionBeginFromCurrentState

Start the animation from the current setting associated with an already in-flight animation. If this key is not present, any in-flight animations are allowed to finish before the new animation is started. If another animation is not in flight, this key has no effect.

If you want to chain a series of animations, here's what I would do:

Create a mutable array of animation blocks. (code blocks are objects, and can be added to an array.) Write a method that pulls the top animation block off the array (and removes it from the array) and submits it using animateWithDuration:animations:completion, where the completion method simply invokes the method again. Make the code assert a lock before pulling an item off the array, and free the lock after deleting the item.

Then you can write code that responds to an incoming notification by asserting your animation array lock, adding an animation block to the lock, and releasing the lock.


If it's the same animation that runs every time then you could just have store the number of times that the animation should run (not the same as the repeat count property of the animation).

When you receive the remote notification you increment the counter and call the method that animates if the counter is exactly one. Then in the methodThatAnimates you recursively call yourself in the completion block while decreasing the counter every time. It would look something like this (with pseudocode method names):

- (void)methodThatIsRunWhenTheNotificationIsReceived {
    // Do other stuff here I assume...
    self.numberOfTimesToRunAnimation = self.numberOfTimesToRunAnimation + 1;
    if ([self.numberOfTimesToRunAnimation == 1]) {
        [self methodThatAnimates];
    }
}

- (void)methodThatAnimates {
    if (self.numberOfTimesToRunAnimation > 0) {
        // Animation preparations ...
        [UIView animateWithDuration:1 
                         animations:^{
                                  customView.alpha = 0.3;
                         } 
                         completion:^(BOOL finished){
                                  // Animation clean up ...
                                  self.numberOfTimesToRunAnimation = self.numberOfTimesToRunAnimation - 1;
                                  [self methodThatAnimates];
                         }];
    }
}

You could use a (non) concurrent NSOperationQueue to perform the animations "step by step"

The NSOperationQueue class regulates the execution of a set of NSOperation objects. After being added to a queue, an operation remains in that queue until it is explicitly canceled or finishes executing its task. Operations within the queue (but not yet executing) are themselves organized according to priority levels and inter-operation object dependencies and are executed accordingly. An application may create multiple operation queues and submit operations to any of them.

Inter-operation dependencies provide an absolute execution order for operations, even if those operations are located in different operation queues. An operation object is not considered ready to execute until all of its dependent operations have finished executing. For operations that are ready to execute, the operation queue always executes the one with the highest priority relative to the other ready operations.