The following code eventually crashes if I draw in a row after delete any row. I believe this happens because there is a memory leak who prevents the UIView of a UIViewRepresentable to be dismantled after deleting elements of the ForEach data. Then the canvasViewDrawingDidChange method for the leaked coordinator is called and drawing doesn't exist in memory anymore.
struct ContentView: View {
@State var models = [Model(), Model(), Model(), Model(), Model()]
var body: some View {
List {
ForEach($models) { $model in
PKCanvasViewRepresentable(drawing: $model.drawing)
}
.onDelete {
models.remove(atOffsets: $0)
}
}
}
}
struct Model: Identifiable {
let id = UUID()
var drawing = PKDrawing()
}
struct PKCanvasViewRepresentable: UIViewRepresentable {
class Coordinator: NSObject, PKCanvasViewDelegate {
@Binding var drawing: PKDrawing
init(drawing: Binding<PKDrawing>) {
self._drawing = drawing
}
func canvasViewDrawingDidChange(_ canvasView: PKCanvasView) {
DispatchQueue.main.async {
self.drawing = canvasView.drawing
// 💥 Swift/ContiguousArrayBuffer.swift:600: Fatal error: Index out of range
}
}
}
@Binding var drawing: PKDrawing
func makeCoordinator() -> Coordinator {
.init(drawing: $drawing)
}
func makeUIView(context: Context) -> PKCanvasView {
let uiView = PKCanvasView()
uiView.delegate = context.coordinator
uiView.drawingPolicy = .anyInput
uiView.drawing = drawing
return uiView
}
func updateUIView(_ uiView: PKCanvasView, context: Context) {
print(#function)
if uiView.drawing != drawing {
uiView.drawing = drawing
}
}
static func dismantleUIView(_ uiView: PKCanvasView, coordinator: Coordinator) {
print(#function)
}
}
Regardless the memory leak I've already filled a feedback (FB11979117) and posted in the Apple Developers Forum but I wonder if there is way to check if the address of drawing is valid or something like that to prevent my app from crashing despite the memory leak.