I have a simple view that uses UITouch events to draw a UIBezierPath. It all works fine until I try to clear the view. Specifically, it works twice, and on the third attempt to draw a line, the app crashes.
For an extra bit of complexity, the UIViewController
is wrapped in a UIViewControllerRepresentable
for use in a SwiftUI project, although my gut instinct is that this isn't the cause of the problem.
Here's the code, and I've isolated the one line that's causing the crash, I just don't know why it's causing the crash.
import UIKit
class Canvas: UIView {
var lineColor: UIColor!
var lineWidth: CGFloat!
var path: UIBezierPath!
var touchPoint: CGPoint!
var startingPoint: CGPoint!
override func layoutSubviews() {
self.clipsToBounds = true;
self.isMultipleTouchEnabled = false;
lineColor = .white
lineWidth = 10
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch = touches.first else { return }
startingPoint = touch.location(in: self)
if(path != nil && path.isEmpty == false) {
clearCanvas()
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch = touches.first else { return }
touchPoint = touch.location(in: self)
path = UIBezierPath()
path.move(to: startingPoint)
path.addLine(to: touchPoint)
startingPoint = touchPoint
drawShapeLayer()
}
func drawShapeLayer() {
let shapeLayer = CAShapeLayer()
shapeLayer.path = path.cgPath
shapeLayer.strokeColor = lineColor.cgColor
shapeLayer.lineWidth = lineWidth
shapeLayer.fillColor = UIColor.clear.cgColor
self.layer.addSublayer(shapeLayer)
self.setNeedsDisplay()
}
func clearCanvas() {
path?.removeAllPoints()
// The next line causes the crash
self.layer.sublayers?.forEach{ $0.removeFromSuperlayer() }
}
}
I'm perpetually a Swift noob. Coming from Javascript, I don't have a great understanding of references and pointers and what not. My suspicion is that something related to the layers is disappearing and then the app is trying to access it, but I can't pin point where or why that's happening. I assumed the views layer
and layer.subLayers
property would always be there.
As always, any help is very much appreciated.
EDIT:
With Zombies enabled in Diagnostics, I get this error
DowntownControls[7663:5124409] *** -[CALayer convertPoint:fromLayer:]: message sent to deallocated instance 0x1070790f0