Raw Bit Rabbit
Raw Bit Rabbit

Reputation: 638

SwiftUI - How to Save selected Image to CoreData and Retrieve it from another View

I'm using an image picker that allows the user to upload a profile picture. However I do not know how to save the image after its selected. This is the image picker code I'm using. Once saved I would also like to retrieve the image in another view and display it.

image!
    .resizable()
    .aspectRatio(contentMode: .fill)
    .frame(width: 150, height: 150)
    .clipShape(Circle())
    .overlay(Circle().stroke(Color.white, lineWidth: 4))
    .shadow(radius: 10)
    .onTapGesture { self.shouldPresentActionScheet = true }
    .sheet(isPresented: $shouldPresentImagePicker) {
        SUImagePickerView(sourceType: self.shouldPresentCamera ? .camera : .photoLibrary, image: self.$image, isPresented: self.$shouldPresentImagePicker)
    }.actionSheet(isPresented: $shouldPresentActionScheet) { () -> ActionSheet in
        ActionSheet(title: Text("Choose mode"), message: Text("Please choose your preferred mode to set your profile image"), buttons: [ActionSheet.Button.default(Text("Camera"), action: {
            self.shouldPresentImagePicker = true
            self.shouldPresentCamera = true
        }), ActionSheet.Button.default(Text("Photo Library"), action: {
            self.shouldPresentImagePicker = true
            self.shouldPresentCamera = false
        }), ActionSheet.Button.cancel()])
        
    }

Upvotes: 0

Views: 1274

Answers (1)

Roma Kavinskyi
Roma Kavinskyi

Reputation: 313

It's not a good practice to save Image to Core Data, as you you'll need to encode into data while saving and decoding from data while retrieving. Also, I've read there are performance issues. The best practice is to use local storage to save an image, and Core Data saves a path to the image in storage. It can be completed like this. It's a good practice to set a unique image name like UUID()

func saveToDocumentDirectory(imageId: String) {
        if let image = takenImage, let data = image.jpegData(compressionQuality: 0.7) {
            do {
                let filename = getDocumentsDirectory().appendingPathComponent(imageId)
                try data.write(to: filename, options: [[.atomicWrite, .completeFileProtection]])
            } catch {
                print("error saving data")
            }
        }
    }

You can call this function when you create a Core Data object like

saveToDocumentDirectory(imageId: object.id.uuidString)

Image can be retrieved with this method:

func retrieveImage(with id: UUID) {
    let dummyImage = Image(systemName: "person")
        do {
            let filename = getDocumentsDirectory().appendingPathComponent(id.uuidString)
            let data = try Data(contentsOf: filename)
            if let uiImage = UIImage(data: data) {
                return Image(uiImage: uiImage)
            }
        } catch {
            print("error loading data")
            return dummyImage
        }
        return dummyImage
}

Try using this image picker


import SwiftUI

struct ImagePicker: UIViewControllerRepresentable {
    @Environment(\.presentationMode) var presentationMode
    @Binding var takenPicture: UIImage?
    
    class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
        var parent: ImagePicker
        
        init(_ parent: ImagePicker) {
            self.parent = parent
        }

        func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
            if let image = info[.originalImage] as? UIImage {
                parent.takenPicture = image
            }

            parent.presentationMode.wrappedValue.dismiss()
        }
    }
    
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    func makeUIViewController(context: Context) -> UIImagePickerController {
        let picker = UIImagePickerController()
        picker.sourceType = .camera
        picker.allowsEditing = false
        picker.cameraFlashMode = UIImagePickerController.CameraFlashMode.off
        picker.delegate = context.coordinator
        return picker
    }
    
    func updateUIViewController(_ uiViewController: UIImagePickerController, context: Context) {}
}

Upvotes: 2

Related Questions