【问题标题】:SwiftUI ImagePicker save (Image -> UIImage --> Data) to Core DataSwiftUI ImagePicker 保存(图像-> UIImage--> 数据)到核心数据
【发布时间】:2020-10-31 00:23:18
【问题描述】:

大家好,我有点沮丧,所以我希望能得到一些帮助。我的项目在 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")
            }
        }
    }
}

【问题讨论】:

  • SwiftUI Image is-a View,你从图像选择器中获得UIImage,将其保留为模型并在两个地方使用:并在Image中显示并存储在数据库中。
  • 您好 Asperi,感谢您的回答。我正在使用的 ImagePicker 将图像作为图像处理。我不太确定如何处理它。我希望直接显示所选图像。你能给我更多的信息吗?谢谢。
  • 好的,谢谢,我用了另一个ImagePicker:hackingwithswift.com/forums/swiftui/…
  • 可能的简单方法 -> stackoverflow.com/questions/65614931/…

标签: core-data swiftui imagepicker


【解决方案1】:

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

您的 ImagePicker 所做的是更改 Image 的 @State。您显示该图像,然后将显示您选择的图像。这里一切都很好。但是,您将无法获取图像的 UIImage。看Image类的接口是不可能的。

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

我不确定您使用的是哪个 ImagePicker。但是,您可以简单地修改版本here 以返回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 以保持对它的引用。

【讨论】:

    【解决方案2】:

    下面是我现有应用程序中的几行代码,我已对其进行了简化。我的方法是简单地从 Image Picker 取回图像数据,而不是 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) {  }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-05-05
      • 1970-01-01
      • 1970-01-01
      • 2017-07-17
      • 1970-01-01
      • 2021-10-21
      • 1970-01-01
      相关资源
      最近更新 更多