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()
}
}