I have a Core Data Project that has 2 entities
Drawing (one to many relationship with Frame)
Frame - has an attribute called canvasDrawing that holds data of a PKDrawing.
When I am trying to switch frames (because this is an animation app): 1st, the drawing layers itself in the first of the array that holds the frames 2nd, I can never see any other more frames apart from the first frame in the array.
struct DrawingView: View {
@Environment(\.managedObjectContext) var viewContext
@State var id:UUID?
@State private var data:Data?
@State var title:String?
@State var canvas: Drawing
@State private var selectedFrame: Int = 0
@State private var frames: [Frame] = []
var body: some View {
VStack{
if frames.isEmpty {
DrawingCanvasView(data: Data(), id: canvas.id!, frames: frames, frameIndex: $selectedFrame, canvas: canvas)
.environment(\.managedObjectContext, viewContext)
} else {
DrawingCanvasView(data: frames[selectedFrame].canvasData ?? Data(), id: canvas.id!, frames: frames, frameIndex: $selectedFrame, canvas: canvas)
.environment(\.managedObjectContext, viewContext)
}
HStack {
ForEach(frames.indices, id: \.self) { frame in
Button {
if selectedFrame != frame {
selectedFrame = frame
}
} label: {
Image(systemName: "photo")
Text(String(frame + 1))
}
.padding()
Divider()
}
// Add Frame
Button {
let frame = Frame(context: viewContext)
frame.duration = 1
frame.canvasData = Data()
canvas.addToFrames(frame)
do {
try viewContext.save()
} catch {
print(error)
}
frames.append(frame)
} label: {
Image(systemName: "plus")
}
}
.frame(height: 50)
}
.task {
let newArray = canvas.frames?.allObjects as! [Frame]
frames = newArray
}
.onChange(of: selectedFrame) { newValue in
DrawingCanvasViewController().drawingData = Data()
DrawingCanvasViewController().drawingData = frames[newValue].canvasData!
}
}
}
DrawingCanvasView:
struct DrawingCanvasView: UIViewControllerRepresentable {
@Environment(\.managedObjectContext) private var viewContext
@State var data: Data
@State var id: UUID
@State var frames: [Frame]
@Binding var frameIndex: Int
@State var canvas: Drawing
func updateUIViewController(_ uiViewController: DrawingCanvasViewController, context: Context) {
uiViewController.drawingData = data
}
typealias UIViewControllerType = DrawingCanvasViewController
func makeUIViewController(context: Context) -> DrawingCanvasViewController {
let viewController = DrawingCanvasViewController()
viewController.drawingData = data
viewController.drawingChanged = { data in
let request: NSFetchRequest<Drawing> = Drawing.fetchRequest()
let predicate = NSPredicate(format: "id == %@", id as CVarArg)
request.predicate = predicate
do {
let result = try viewContext.fetch(request)
if let drawing = result.first {
guard frameIndex < drawing.frames?.count ?? 0 else {
print("Invalid frame index")
return
}
if let framesArray = drawing.frames?.allObjects as? [Frame] {
let frameToUpdate = framesArray[frameIndex]
frameToUpdate.canvasData = data
do {
try viewContext.save()
} catch {
print(error)
}
print("Updated data at index: \(frameIndex)")
}
}
} catch {
print(error)
}
}
return viewController
}
}
Finally, DrawingCanvasViewController:
class DrawingCanvasViewController: UIViewController {
lazy var canvas: PKCanvasView = {
let view = PKCanvasView()
view.drawingPolicy = .anyInput
view.minimumZoomScale = 1
view.maximumZoomScale = 1
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
var drawingData = Data()
var drawingChanged: (Data) -> Void = {_ in}
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(canvas)
NSLayoutConstraint.activate([
canvas.leadingAnchor.constraint(equalTo: view.leadingAnchor),
canvas.trailingAnchor.constraint(equalTo: view.trailingAnchor),
canvas.topAnchor.constraint(equalTo: view.topAnchor),
canvas.bottomAnchor.constraint(equalTo: view.bottomAnchor)])
canvas.delegate = self
canvas.becomeFirstResponder()
if let drawing = try? PKDrawing(data: drawingData){
canvas.drawing = drawing
}
}
}
I can confirm that in the makeUI
function of the DrawingCanvasView, it is saving to the right index, but I cannot see that frame (at that index) in the DrawingView.
It is probably a lot to read, but please any suggestions are greatly appreciated, I am not sure where I am going wrong.