3

大家好,我有点沮丧,所以我希望能得到一些帮助。我的项目在 SwiftUI 中。我想使用图像选择器将图像保存到核心数据。我实现了让 ImagePicker 工作,但我努力转换 Image --> UIImage --> Data 然后保存它。项目运行没有错误,但它不保存图像。要知道问题在哪里,我实施了 3 个打印语句。image=给了一个值,UIImage(inputImage)=nil,Data当然是nil。

import SwiftUI


struct AddNewBean: View {
    
    @Environment(\.presentationMode) var presentationMode
    @Environment(\.managedObjectContext) var moc
    @FetchRequest(entity: Bean.entity(), sortDescriptors: []) var beans: FetchedResults<Bean>
    @State var BeanRoaster: String = ""
    @State var BeanName: String = ""
    @State var BeanStyle: String = "Dark"
    
    @State private var RoastDate = Date()
        var dateFormatter: DateFormatter {
        let formatter = DateFormatter()
        formatter.dateStyle = .long
        return formatter }
    
    @State private var showImagePicker : Bool = false
    @State private var image : Image?
    @State private var inputImage: UIImage?
    @State var imageAlt: Data = .init(count: 0)
    
    let RStyles = ["Dark", "Medium", "Light"]
    
    func loadImage() {
        guard let inputImage = inputImage else { return }
        image = Image(uiImage: inputImage)
    }
    
    var body: some View {
        
        NavigationView {
            VStack {
                Form {
                    VStack {
                        image?.resizable().scaledToFit().aspectRatio(contentMode: .fit)
                        HStack {
                            Spacer()
                            Button("Open Camera"){
                                self.showImagePicker = true
                            }.padding(5)
                                .foregroundColor(Color.white)
                                .background(Color.accentColor)
                                .cornerRadius(10)
                            Spacer()
                        }.sheet(isPresented: self.$showImagePicker, onDismiss: loadImage){
                            PhotoCaptureView(showImagePicker: self.$showImagePicker, image: self.$image)
                        }
                    }
                    TextField("Röster", text: $BeanRoaster)
                    TextField("Name der Bohne", text: $BeanName)
                    Picker("Roestung", selection: $BeanStyle) {
                        ForEach(RStyles, id: \.self) {
                            Text($0)
                        }
                    }
                    DatePicker(selection: $RoastDate, in: ...Date(), displayedComponents: .date) {Text("Röstdatum")}
   
                    HStack {
                        Spacer()
                        if BeanRoaster != "" && BeanName != "" {
                            Button(action: {
                                //....
                                let pickedImage = self.inputImage?.jpegData(compressionQuality: 1.0)
                                                                print("image, inputimage, pickedImage")
                                print(self.image as Any) // prints:  Optional(SwiftUI.Image(provider: SwiftUI.ImageProviderBox<__C.UIImage>))
                                print(self.inputImage as Any) // prints: nil
                                print(pickedImage as Any) // prints: nil
                                //.....
                                let bean = Bean(context: self.moc)
                                bean.id = UUID()
                                bean.roaster = "\(self.BeanRoaster)"
                                bean.name = "\(self.BeanName)"
                                bean.roastStyle = "\(self.BeanStyle)"
                                bean.roastDate = self.RoastDate
                                bean.active = true
                                bean.img = pickedImage
                                
                                try? self.moc.save()
                                self.presentationMode.wrappedValue.dismiss()
                            }) {
                                Image(systemName: "tray")
                                    .foregroundColor(.blue)
                                    .font(.largeTitle)
                                    .padding(.vertical)
                            }
                            Text("Save").foregroundColor(.blue)
                            Spacer()
                        } else {
                            HStack {
                                Spacer()
                                Text("Trage Bohnendaten ein!")
                                Spacer()
                            }
                        } 
                    } 

                    Section {
                        HStack {
                            Spacer()
                            Button(action: {self.presentationMode.wrappedValue.dismiss()}) {
                                Image(systemName: "")
                                    .foregroundColor(.red)
                                    .font(.largeTitle)
                                    .padding(.vertical)
                            }
                            Text("Dismiss").foregroundColor(.red)
                            Spacer()
                        }
                    }
                }.navigationBarTitle("New Bean")
            }
        }
    }
}
4

2 回答 2

4

下面是我现有应用程序中的几行代码,我已经对其进行了简化。我的方法是简单地从图像选择器中取回图像数据,而不是 UIImage。这对我有用。

ContentView

struct ContentView: View {
    @Environment(\.managedObjectContext) var viewContext
    
    @FetchRequest(entity: Images.entity(), sortDescriptors: [], animation: Animation.easeInOut)
    var images: FetchedResults<Images>
    
    @State private var showImagePicker = false
    @State private var image = Image(systemName: "person.circle.fill")
    @State private var data: Data?
    @State private var optionalData = UIImage(systemName: "person.circle.fill")?.jpegData(compressionQuality: 1)
    
    var body: some View {
        VStack {
            ForEach(images) { image in
                Image(uiImage: UIImage(data: (image.imageData ?? optionalData)!)!)
                    // your modifiers
            }
            
            image
                .resizable()
                .frame(width: 150, height: 150)
            
            Button(action: {
                showImagePicker = true
            }) {
                Text("Select")
            }
            
            Button(action: {
                let newImage = Images(context: viewContext)
                newImage.imageData = data

                do {
                    try viewContext.save()
                    print("Image Saved!")
                } catch {
                    print(error.localizedDescription)
                }
            }) {
                Text("Save")
            }
        }
        .sheet(isPresented: $showImagePicker, onDismiss: loadImage) {
            ImagePicker(data: $data)
        }
    }
    
    func loadImage() {
        guard let data = data else { return }
        
        image = Image(uiImage: UIImage(data: data) ?? UIImage(systemName: "person.circle.fill")!)
    }
}

ImagePicker

struct ImagePicker: UIViewControllerRepresentable {
    @Environment(\.presentationMode) var presentationMode
    @Binding var data: Data?
    
    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 uiImage = info[.originalImage] as? UIImage {
                parent.data = uiImage.jpegData(compressionQuality: 1)
            }
            parent.presentationMode.wrappedValue.dismiss()
        }
    }
    
    func makeUIViewController(context: Context) -> UIImagePickerController {
        let picker = UIImagePickerController()
        picker.allowsEditing = true
        picker.sourceType = .photoLibrary
        picker.delegate = context.coordinator
        
        return picker
    }
    
    func makeCoordinator() -> Coordinator { Coordinator(self) }
    
    func updateUIViewController(_ uiViewController: UIImagePickerController, context: Context) {  }
}
于 2020-10-02T09:13:06.297 回答
1

上面的代码有一些错误。我重新创建了解决方案,其中还包含更改 ImagePicker。

你的 ImagePicker 做了什么,它改变了 @State 的Image. 您显示该图像,然后将显示您选择的图像。这里一切都很好。但是,您将无法获取图像的 UIImage。如果您查看类的接口,这是不可能的Image

让你的图像选择器返回一个 UIImage

我不确定您使用的是哪个 ImagePicker。但是,您可以在此处简单地修改版本以返回UIImage.

如果显示 imagePicker 和 UIImage,我们只存储一个布尔值。

@State private var showImagePicker : Bool = false
@State private var image : UIImage?

每当 UIImage 发生变化时,您都可以更新您的 Image。只需使用:

if (self.image != nil)
{
    Image(uiImage: self.image!).resizable().scaledToFit().aspectRatio(contentMode: .fit)
}

现在,当您将 UIImage 存储到数据库时,您需要将其转换为 Data 对象。这很简单。

Button(action: {
    
    //Not nil
    print(self.image)

    //PNG Representation as Data
    let imageData = self.image!.pngData()
    
    //Data type here --> Data
    print(type(of: imageData))

在这里你看,它来自对象Data,数据可以简单地存储在 CoreData 中。

您仍然需要解决的唯一问题是您没有将图像绑定传递给您的 ImagePicker,而是将绑定作为 UIImage 传递。

看起来像这样:

struct CaptureImageView {
    
    @Binding var isShown: Bool
    @Binding var image: UIImage?
    
    func makeCoordinator() -> Coordinator {
      return Coordinator(isShown: $isShown, image: $image)
    }
}

而在 中didFinishPickingMediaWithInfo,您只需设置 UIImage.

func imagePickerController(_ picker: UIImagePickerController,
            didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
 guard let unwrapImage = info[UIImagePickerController.InfoKey.originalImage] as? UIImage else { return }
 imageInCoordinator = unwrapImage
 isCoordinatorShown = false
}

同样,这不是我的 ImagePicker。我只是为您修改了它,以明确什么是错误的以及您需要修复什么。我在这里得到了一个可行的解决方案,这是可能的。只需确保您使用的是什么,而不是 Image,而是 UIImage 以保持对它的引用。

于 2020-07-11T10:16:18.537 回答