Chapter 9 - Challenge Moving Clouds Solution - Bug?

I’ve tried the challenge in Chapter 9 to move the clouds. But once the cloud initially finishes the animation and when I try to reset it, the cloud will flash real quick where it was originally in the view and then start where it’s supposed to.

I’ve checked the solution provided but it does the same thing as mine. Has anyone else noticed this? I can’t seem to figure out how to solve this.

Edit:
Well one way to fix it I found was to add these two lines of code to “animateCloud(layer: CALayer)”

    cloudMove.fillMode = kCAFillModeForwards
    cloudMove.isRemovedOnCompletion = false

But I’d prefer not to use isRemovedOnCompletion for performance reasons. Not sure if there’s a better way though.

Thanks,
Eric

I’d really like to see a solution to this bug; I’ve tried a number of things, mostly involving changing the starting position of the clouds off-screen in Interface Builder, then changing the cloud’s center x positions in viewDidLoad, but doing that makes the “flash” even worse by lasting longer.

Interestingly, the flash only occurs the first time that the animation loops, and then works fine on each subsequent loop.

OK, i found a solution:

In animateCloud(layer) find the following line:

let cloudMove = CABasicAnimation(keyPath: "position.x")

Then add the following lines below it:

cloudMove.fillMode = kCAFillModeForwards
cloudMove.isRemovedOnCompletion = false

Next, change this line:

layer.add(cloudMove, forKey: nil)

to this:

layer.add(cloudMove, forKey: "cloudAnimation")

Lastly, in animationDidStop(_:finished) change your code to look like this:

if name == "cloud" {
     if let layer = anim.value(forKey: "layer") as? CALayer {
          anim.setValue(nil, forKey: "layer")

          layer.position.x = -layer.bounds.width/2
          layer.removeAllAnimations()

          delay(seconds: 0.5) {
               self.animateCloud(layer: layer)
          }
     }
}

That’s it!

Now the strange part (there is always a strange part…):

In animationDidStop(_:finished), move the following line outside delay(seconds):

self.animateCloud(layer: layer)

and put it after the following line:

layer.removeAllAnimations()

Build and Run. Everything is still working great. Now in animateCloud(layer), change this line:

layer.add(cloudMove, forKey: "cloudAnimation")

back to this:

layer.add(cloudMove, forKey: nil)

Build and Run. Now the animation is not working as expected…

The thing is i didn’t figured out why this stops working if we don’t use a key, despite the fact that we never use it.

Any thoughts? :roll_eyes:

@icanzilb Can you please provide any feedback on this? Thank you - much appreciated! :]

you can safely use isRemovedOnCompletion; when you update manually the animated property or animate it again that safely removes the previous animation

But when you use isRemovedOnCompletion = true (default), the ‘blink’ side effect (as described in the original post) emerges. The whole point of my solution and the use of isRemovedOnCompletion = false is to troubleshoot this problem… Do i miss something?

hmm, let me run the code here and I’ll come back to you … maybe they changed something recently? I must say I haven’t seen a blink myself previously

1 Like