Search code examples
macoscocoacore-animationcalayernsview

Layer backed NSView problems in viewDidLoad


I set off to transform an NSImageView. My initially attempt was

self.imageView.wantsLayer = YES;
self.imageView.layer.transform = CATransform3DMakeRotation(1,1,1,1);

Unfortunately I noticed that the transform only happens sometimes (maybe once every 5 runs). Adding an NSLog between confirmed that on some runs self.imageView.layer is null. State of the whole project is shown on the image below.

Project state

It's an incredibly simple 200x200 NSImageView with an outlet to a generated NSViewController. Some experimentation showed settings wantsDisplay doesn't fix the problem, but putting the transform on an NSTimer makes it work every-time. I'd love an explanation why this happens (I presume it's due to some race condition).

I'm using Xcode 8 on the macOS 10.12 but I doubt this is the cause of the problem.

Update

Removing wantsLayer and madly enabling Core Animation Layers in Interface Builder did not fix the problem.

Ticked core animation layers

Neither did attempts to animate it (I wasn't sure what I was hoping for)

// Sometimes works.. doesn't animate
[NSAnimationContext runAnimationGroup:^(NSAnimationContext *context) {
    context.duration = 1;
    self.imageView.animator.layer.transform = CATransform3DMakeRotation(1,1,1,1);
} completionHandler:^{
    NSLog(@"Done");
}];

or

// Animates but only sometimes
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform"];
animation.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(1,1,1,1)];
animation.duration = 1;
[self.imageView.layer addAnimation:animation forKey:nil];

Solution

  • After experimenting with allowsImplicitAnimation I realised I might be trying to animate too early.

    Moving the transform code into viewDidAppear made it work every time.

    - (void)viewDidAppear {
        [super viewDidAppear];
        self.imageView.animator.layer.transform = CATransform3DMakeRotation(1,1,1,1);
    }