SwiftUI ImagePicker 保存(图像-> UIImage--> 数据)到核心数据
Posted
技术标签:
【中文标题】SwiftUI ImagePicker 保存(图像-> UIImage--> 数据)到核心数据【英文标题】:SwiftUI ImagePicker save (Image -> UIImage --> Data) to Core Data 【发布时间】: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")
【问题讨论】:
SwiftUIImage
is-a View,你从图像选择器中获得UIImage
,将其保留为模型并在两个地方使用:并在Image
中显示并存储在数据库中。
您好 Asperi,感谢您的回答。我正在使用的 ImagePicker 将图像作为图像处理。我不太确定如何处理它。我希望直接显示所选图像。你能给我更多的信息吗?谢谢。
好的,谢谢,我用了另一个ImagePicker:hackingwithswift.com/forums/swiftui/…
可能的简单方法 -> ***.com/questions/65614931/…
【参考方案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)
【讨论】:
以上是关于SwiftUI ImagePicker 保存(图像-> UIImage--> 数据)到核心数据的主要内容,如果未能解决你的问题,请参考以下文章
如何正确地将 ImagePicker 插入标题中的图像? SwiftUI
如何将您使用 imagepicker 上传的照片保存为新帖子?
ImagePicker 选择图像后,CollectionView 图像不更新