I'm trying to evolve my app to save an array of images in Core Data instead of pre-defined attributes of an Entity. Today, my Entity has 4 image attributes, and the user saves 4 images as 4 separate actions within the app. It works.
Now I'm trying to implement VisionKit
so the user can just auto scan and crop the images one after another, and then save one time to get multiple images saved. I have the scan piece working:
import SwiftUI
import VisionKit
struct ScannerView: UIViewControllerRepresentable {
@Binding var images: [Data]
var didFinishScanning: ((_ result: Result<[UIImage], Error>) -> Void)
var didCancelScanning: () -> Void
func makeUIViewController(context: Context) -> VNDocumentCameraViewController {
let scannerViewController = VNDocumentCameraViewController()
scannerViewController.delegate = context.coordinator
return scannerViewController
}
func updateUIViewController(_ uiViewController: VNDocumentCameraViewController, context: Context) { }
func makeCoordinator() -> Coordinator {
Coordinator(with: self)
}
class Coordinator: NSObject, VNDocumentCameraViewControllerDelegate {
let scannerView: ScannerView
init(with scannerView: ScannerView) {
self.scannerView = scannerView
}
// MARK: - VNDocumentCameraViewControllerDelegate
func documentCameraViewController(_ controller: VNDocumentCameraViewController, didFinishWith scan: VNDocumentCameraScan) {
var scannedPages = [UIImage]()
for i in 0..<scan.pageCount {
scannedPages.append(scan.imageOfPage(at: i))
let image = scan.imageOfPage(at: i)
scannerView.images.append( image.jpegData(compressionQuality: 0.55)! )
}
scannerView.didFinishScanning(.success(scannedPages))
controller.dismiss(animated: true, completion: nil)
}
func documentCameraViewControllerDidCancel(_ controller: VNDocumentCameraViewController) {
scannerView.didCancelScanning()
}
func documentCameraViewController(_ controller: VNDocumentCameraViewController, didFailWithError error: Error) {
scannerView.didFinishScanning(.failure(error))
}
}
}
And can immediately view the images in the View
LazyHStack {
ForEach(0..<images.count, id: \.self) { imageIdx in
Image(uiImage: UIImage(data: self.images[imageIdx])!)
.resizable()
.cornerRadius(6)
.scaledToFit()
.frame(width: self.width, height: self.height)
}
}
Here's a quick video showing everything to this point: https://i.sstatic.net/dAC10.jpg
I'm stuck trying to properly save the array of images. I get error Value of type 'CapturedImage' has no member 'append'
for image in images {
let capImage = CapturedImage(context: viewContext)
capImage.image = image
capImage.timestamp = Date()
project.capturedimage?.append(capImage) --->>> error
}
My CapturedImage+CoreDataProperties.swift
looks like this:
import Foundation
import CoreData
extension CapturedImage {
@nonobjc public class func fetchRequest() -> NSFetchRequest<CapturedImage> {
return NSFetchRequest<CapturedImage>(entityName: "CapturedImage")
}
@NSManaged public var image: Data?
@NSManaged public var timestamp: Date?
@NSManaged public var project: Project?
}
extension CapturedImage : Identifiable {
}
And here is the relationship between Project
and CapturedImage
entities (you'll also notice the image1
image2
image3
image4
attributes that currently work for single image saves...
What do I need to do in order to overcome that append
error above?
Am I on the right track for saving the array to CD properly?
Apologies for the length of this post! I wanted to provide as much info as I could while trying to keep it brief. Thanks for looking
According to your model capturedimage
in Project
is a To Many relationship, the type is NSSet
or Set<CapturedImage>
. And the naming is misleading, it should be named in plural form capturedImages
.
Sets are unordered, you have to insert the object. Depending on your settings Core Data might create a convenient setter addToCapturedImages
on your behalf
project.addToCapturedImages(capImage)
Please see Generating Code in the documentation.