The Problem
I have two view controllers, both are contained within respective UINavigationController
s and a single UITabBarController
. On one of the view controllers I am creating a bubbles effect, where I draw bubbles on the screen and animate their positions. The problem occurs when I move to the other view controller using the tab bar, this causes the CPU to spike and remain at 100% and the bubbles to continue to animate.
Code
The code for the bubbles is encapsulated within a UIView
subclass.
override func draw(_ rect: CGRect) {
// spawn shapes
for _ in 1 ... 10 { // spawn 75 shapes initially
spawn()
}
}
The drawRect
method repeatedly calls the spawn
function to populate the view with bubbles.
fileprivate func spawn() {
let shape = CAShapeLayer()
shape.opacity = 0.0
// create an inital path at the starting position
shape.path = UIBezierPath(arcCenter: CGPoint.zero, radius: 1, startAngle: 0, endAngle: 360 * (CGFloat.pi / 180), clockwise: true).cgPath
shape.position = CGPoint.zero
layer.addSublayer(shape)
// add animation group
CATransaction.begin()
let radiusAnimation = CABasicAnimation(keyPath: "path")
radiusAnimation.fromValue = shape.path
radiusAnimation.toValue = UIBezierPath(arcCenter: center, radius: 100, startAngle: 0, endAngle: 360 * (CGFloat.pi / 180), clockwise: true).cgPath
CATransaction.setCompletionBlock { [unowned self] in
// remove the shape
shape.removeFromSuperlayer()
shape.removeAllAnimations()
// spawn a new shape
self.spawn()
}
let movementAnimation = CABasicAnimation(keyPath: "position")
movementAnimation.fromValue = NSValue(cgPoint: CGPoint.zero)
movementAnimation.toValue = NSValue(cgPoint: CGPoint(x: 100, y: 100))
let animationGroup = CAAnimationGroup()
animationGroup.animations = [radiusAnimation, movementAnimation]
animationGroup.fillMode = kCAFillModeForwards
animationGroup.isRemovedOnCompletion = false
animationGroup.duration = 2.0
shape.add(animationGroup, forKey: "bubble_spawn")
CATransaction.commit()
}
Within the CATransaction
completion handler I remove the shape from the superview and create a new one. The function call to self.spawn()
seems to be the problem
On viewDidDisappear
of the containing view controller I call the following:
func removeAllAnimationsFromLayer() {
layer.sublayers?.forEach({ (layer) in
layer.removeAllAnimations()
layer.removeFromSuperlayer()
})
CATransaction.setCompletionBlock(nil)
}
Attempts from answers
I've tried to add the removeAllAnimations
function to the UITabBarControllerDelegate
extension BaseViewController: UITabBarControllerDelegate {
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
bubblesView.removeAllAnimationsFromLayer()
}
}
self.spawn()
fromcompletionBlock
? – Leespawn
or not. Just a thought :D – Leecompletion
block you calling animate start again, which means you are on arecursion
with infinite loop, that's why its animating all the time, you just need to control and stop that animation! – LeeremovedOnCompletion
flag tofalse
. In the code accompanying my question you can see that the flag is already being set tofalse
and the problem persists. – Museology