swift core-data uiimage uiimagepickercontroller

swift - Guardar la imagen seleccionada en CoreData



core-data uiimage (2)

Puedo seleccionar y mostrar una imagen de la biblioteca de fotos, pero mi objetivo es poder guardar esa imagen elegida o la ruta del archivo a los datos centrales para que cuando se seleccione ese registro guardado, esa imagen también se muestre.

Tengo CoreData funcionando y puedo mostrar bien el texto de CoreData, solo es la imagen que me sostiene.

@IBAction func addPic(sender: AnyObject) { pickerController.delegate = self pickerController.sourceType = UIImagePickerControllerSourceType.PhotoLibrary // 2 self.presentViewController(pickerController, animated: true, completion: nil) // Displays image func imagePickerController(picker: UIImagePickerController!,didFinishPickingMediaWithInfo info: NSDictionary!){ image.image = info[UIImagePickerControllerOriginalImage] as? UIImage self.dismissViewControllerAnimated(true, completion: nil)


Core Data no está diseñado para guardar grandes archivos binarios como imágenes. Use Document Directory en el sistema de archivos en su lugar.

Aquí hay un código de muestra para lograr eso.

let documentsDirectory = NSSearchPathForDirectoriesInDomains(.DocumentDirectory,.UserDomainMask, true).first as! String // self.fileName is whatever the filename that you need to append to base directory here. let path = documentsDirectory.stringByAppendingPathComponent(self.fileName) let success = data.writeToFile(path, atomically: true) if !success { // handle error }


Pase a Procesar la imagen para descubrir cómo convertir UIImage a NSData (que es lo que usa Core Data)

O descargar desde github

Configuración de datos básicos:

Configure dos entidades: Resolución completa y Miniatura. Resoluciones completas es almacenar la imagen original. Miniatura para almacenar una versión más pequeña para usar dentro de la aplicación. Puede usar una versión más pequeña en una UICollectionView general de UICollectionView por ejemplo.

Las imágenes se almacenan como Binary Data en los Core Data . El tipo correspondiente en Foundation es NSData . Convierte de nuevo a UIImage con UIImage(data: newImageData)

Marque la casilla Permitir almacenamiento externo para los campos de Datos binarios. Esto guardará automáticamente las imágenes en el sistema de archivos y las referenciará en Core Data

Conecte las dos entidades, creando una relación uno a uno entre los dos.

Vaya a Editor en seleccione Crear NSManagedObjectSubclass . Esto generará archivos con Clases que representan sus Subclases de Objetos Administrados. Estos aparecerán en la estructura de su archivo de proyecto.

Configuración básica de ViewController:

Importe lo siguiente:

import UIKit import CoreData

  • Configura dos UIButtons y un UIImageView en el Interface Builder
  • Cree dos colas de envío, una para CoreData y otra para las conversiones de UIImage

class ViewController: UIViewController { // imageview to display loaded image @IBOutlet weak var imageView: UIImageView! // image picker for capture / load let imagePicker = UIImagePickerController() // dispatch queues let convertQueue = dispatch_queue_create("convertQueue", DISPATCH_QUEUE_CONCURRENT) let saveQueue = dispatch_queue_create("saveQueue", DISPATCH_QUEUE_CONCURRENT) // moc var managedContext : NSManagedObjectContext? override func viewDidLoad() { super.viewDidLoad() imagePickerSetup() // image picker delegate and settings coreDataSetup() // set value of moc on the right thread } // this function displays the imagePicker @IBAction func capture(sender: AnyObject) { // button action presentViewController(imagePicker, animated: true, completion: nil) } @IBAction func load(sender: AnyObject) { // button action loadImages { (images) -> Void in if let thumbnailData = images?.last?.thumbnail?.imageData { let image = UIImage(data: thumbnailData) self.imageView.image = image } } } }

Esta función establece un valor para managedContext en el hilo correcto. Dado que CoreData necesita que todas las operaciones en un NSManagedObjectContext sucedan en el mismo hilo.

extension ViewController { func coreDataSetup() { dispatch_sync(saveQueue) { self.managedContext = AppDelegate().managedObjectContext } } }

Extienda el UIViewController para que se ajuste a UIImagePickerControllerDelegate y UINavigationControllerDelegate Estos son necesarios para UIImagePickerController .

Cree una función de configuración y cree también la función de delegado imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage, editingInfo: [String : AnyObject]?)

extension ViewController : UIImagePickerControllerDelegate, UINavigationControllerDelegate { func imagePickerSetup() { imagePicker.delegate = self imagePicker.sourceType = UIImagePickerControllerSourceType.Camera } // When an image is "picked" it will return through this function func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage, editingInfo: [String : AnyObject]?) { self.dismissViewControllerAnimated(true, completion: nil) prepareImageForSaving(image) } }

UIImagePickerController inmediatamente el UIImagePickerController , de lo contrario, la aplicación parecerá congelarse.

Procesando la imagen:

Llame a esta función dentro de imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage, editingInfo: [String : AnyObject]?) .

  • Primero obtenga la fecha actual con timeIntervalSince1970 . Esto devuelve un NSTimerInterval en segundos. Esto se convierte muy bien en un Double . Servirá como una identificación única para las imágenes y como una forma de ordenarlas.

  • Ahora es un buen momento para pasar a la cola separada y liberar la cola principal. dispatch_async(convertQueue) primero para hacer el trabajo pesado en un hilo separado.

  • Entonces necesitas convertir el UIImage a NSData esto se hace con UIImageJPEGRepresentation(image, 1) . El 1 representa la calidad donde 1 es el más alto y 0 es el más bajo. Devuelve un opcional así que utilicé el enlace opcional.

  • Escala la imagen a un tamaño de miniatura deseado y también NSData en NSData .

Código:

extension ViewController { func prepareImageForSaving(image:UIImage) { // use date as unique id let date : Double = NSDate().timeIntervalSince1970 // dispatch with gcd. dispatch_async(convertQueue) { // create NSData from UIImage guard let imageData = UIImageJPEGRepresentation(image, 1) else { // handle failed conversion print("jpg error") return } // scale image, I chose the size of the VC because it is easy let thumbnail = image.scale(toSize: self.view.frame.size) guard let thumbnailData = UIImageJPEGRepresentation(thumbnail, 0.7) else { // handle failed conversion print("jpg error") return } // send to save function self.saveImage(imageData, thumbnailData: thumbnailData, date: date) } } }

Esta función hace el ahorro real.

  • Vaya al subproceso de CoreData con dispatch_barrier_sync(saveQueue)
  • Primero inserte un nuevo FullRes y un nuevo objeto Miniatura en el Contexto del Objeto Administrado.
  • Establecer los valores
  • Establecer la relación entre FullRes y Miniatura
  • Use do try catch para intentar guardar
  • Actualice el contexto del objeto gestionado para liberar memoria

Al usar dispatch_barrier_sync(saveQueue) estamos seguros de que podemos almacenar de manera segura una nueva imagen y de que las nuevas copias o cargas esperarán hasta que esto termine.

Código:

extension ViewController { func saveImage(imageData:NSData, thumbnailData:NSData, date: Double) { dispatch_barrier_sync(saveQueue) { // create new objects in moc guard let moc = self.managedContext else { return } guard let fullRes = NSEntityDescription.insertNewObjectForEntityForName("FullRes", inManagedObjectContext: moc) as? FullRes, let thumbnail = NSEntityDescription.insertNewObjectForEntityForName("Thumbnail", inManagedObjectContext: moc) as? Thumbnail else { // handle failed new object in moc print("moc error") return } //set image data of fullres fullRes.imageData = imageData //set image data of thumbnail thumbnail.imageData = thumbnailData thumbnail.id = date as NSNumber thumbnail.fullRes = fullRes // save the new objects do { try moc.save() } catch { fatalError("Failure to save context: /(error)") } // clear the moc moc.refreshAllObjects() } } }

Para cargar una imagen:

extension ViewController { func loadImages(fetched:(images:[FullRes]?) -> Void) { dispatch_async(saveQueue) { guard let moc = self.managedContext else { return } let fetchRequest = NSFetchRequest(entityName: "FullRes") do { let results = try moc.executeFetchRequest(fetchRequest) let imageData = results as? [FullRes] dispatch_async(dispatch_get_main_queue()) { fetched(images: imageData) } } catch let error as NSError { print("Could not fetch /(error), /(error.userInfo)") return } } } }

Las funciones utilizadas para escalar la imagen:

extension CGSize { func resizeFill(toSize: CGSize) -> CGSize { let scale : CGFloat = (self.height / self.width) < (toSize.height / toSize.width) ? (self.height / toSize.height) : (self.width / toSize.width) return CGSize(width: (self.width / scale), height: (self.height / scale)) } } extension UIImage { func scale(toSize newSize:CGSize) -> UIImage { // make sure the new size has the correct aspect ratio let aspectFill = self.size.resizeFill(newSize) UIGraphicsBeginImageContextWithOptions(aspectFill, false, 0.0); self.drawInRect(CGRectMake(0, 0, aspectFill.width, aspectFill.height)) let newImage:UIImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return newImage } }