0

Say I have a subclass of UIView which I will call AnimatableView, where my implementation of layoutSubviews lays out some internal content.

AnimatableView also has the method commenceAnimationLoop which looks something like this:

- (void) commenceAnimationLoop {

    NSOperation *animationLoop = [[AnimationLoopOperation alloc]init];
    [queue addOperation:animationLoop]; //queue is a NSOperationQueue iVar of AnimatableView
    [animationLoop release];
}

The AnimationLoopOperation is a subclass of NSOperation whose main method will start an infinite animation which only exits once the isCancelled property becomes YES.

The problem I am having is in my ViewController where I setup and animate an instance of AnimatableView like so:

- (void) viewDidLoad {
    AnimatableView *animatableView = [AnimatableView alloc]initWithFrame:someFrame];

    [self.view addSubview: animatableView];
    [animatableView commenceAnimationLoop];

    [animatableView release];
}

The problem is that the NSOperation created in the commenceAnimationLoop executes before my instance of AnimatableView has had chance to call layoutSubviews (meaning that it's content has not yet been generated and laid out).

I am making an educated guess that the layoutSubviews method is called later (when the ViewController is ready to render its view hierarchy?), but that the commenceAnimationLoop method spawns a thread that immediately executes in the background.

To summarise - what would be the best way to make my animationLoop operation wait for the view to layout before commencing?

To provide some high level context for what I am trying to achieve - I am using NSOperation to start a continuous animation. The idea being that I can provide an endAnimation method which would likely call cancelAllOperations on my queue. All this is done in the hopes I can provide a way of starting and then interrupting an infinite animation with the two methods commenceAnimationLoop and endAnimation. Perhaps I am barking up the wrong tree going down the route of multi-threading?

Barjavel
  • 1,626
  • 3
  • 19
  • 31
  • 1
    If you need layoutSubviews to run before your operation then you should't start the operation queue (use `setSuspended:YES`) until it have finished. You could start the operation queue (`setSuspended:NO`) in `viewDidAppear`... – David Rönnqvist May 24 '12 at 10:12
  • The above worked and it's a really simple solution too. Add it as an answer and I'll accept it. – Barjavel May 24 '12 at 21:05

1 Answers1

2

If you need layoutSubviews to run before your operation then you should't start the operation queue before it that. You can prevent an operation queue from starting additional operations using [myOperationQueue setSuspended:YES];.

Since it will only prevent the queue from starting new operations you should suspend the queue before you add your operations to it.

After you view has loaded and layoutSubviews has run you can resume the operation queue again using [myOperationQueue setSuspended:NO];. One place to do this could be in viewDidAppear.

David Rönnqvist
  • 56,267
  • 18
  • 167
  • 205