Go to Process Image to learn how to convert UIImage to NSData (which uses Core Data)
Or download from github
Master data setup:
Set up two objects: Full resolution and thumbnail. Full permissions - keep the original image. A thumbnail for storing a smaller version that will be used inside the application. For example, you can use a smaller version in a UICollectionView .
Images are saved as Binary Data in Core Data . The corresponding type in Foundation is NSData . Return to UIImage with UIImage(data: newImageData)


Select the Allow external storage for binary data fields check box. This will automatically save the images to the file system and contact them in Core Data p>

Connect two objects, creating a relationship between them.

Go to ru Editor , select Create NSManagedObjectSubclass . This will generate files with classes representing subclasses of managed objects. They will appear in your project file structure.

Basic installation of ViewController:
Import the following:
import UIKit import CoreData
- Configure two
UIButtons and UIImageView in the interface builder - Create two send queues, one for CoreData and one for UIImage conversions
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 } } } }
This function sets the managedContext value in the correct thread. Because CoreData requires all operations in the same NSManagedObjectContext performed on the same thread.
extension ViewController { func coreDataSetup() { dispatch_sync(saveQueue) { self.managedContext = AppDelegate().managedObjectContext } } }
Extend the UIViewController to match the UIImagePickerControllerDelegate and UINavigationControllerDelegate They are needed for the UIImagePickerController .
Create a setup function, and also create a delegate function imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage, editingInfo: [String : AnyObject]?)
extension ViewController : UIImagePickerControllerDelegate, UINavigationControllerDelegate { func imagePickerSetup() { imagePicker.delegate = self imagePicker.sourceType = UIImagePickerControllerSourceType.Camera }
Release the UIImagePickerController , otherwise the application will be frozen.
Image processing:
Call this function inside imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage, editingInfo: [String : AnyObject]?) .
First enter the current date using timeIntervalSince1970 . This returns NSTimerInterval in seconds. It converts well to Double . It will serve as a unique identifier for images and as a way to sort them.
Now is the time to move to a separate queue and free the main queue. At first I used dispatch_async(convertQueue) to do a heavy lift on a separate thread.
Then you need to convert the UIImage to NSData , this is done using UIImageJPEGRepresentation(image, 1) . 1 represents quality, where 1 is the highest and 0 is the lowest. It returns optional, so I used optional binding.
Enlarge the image to the desired sketch size, and convert it to NSData .
The code:
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) } } }
This function performs actual savings.
- Go to the CoreData stream with
dispatch_barrier_sync(saveQueue) - First insert the new FullRes and the new Thumbnail into the Managed Object Context.
- Set Values
- Establish Link between FullRes and Thumbnail
- Use
do try catch to try to save - Refresh managed entity context to free memory
Using dispatch_barrier_sync(saveQueue) , we are confident that we can safely store the new image and that the new ones saved or uploaded will wait until it ends.
The code:
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() } } }
To upload an image:
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 } } } }
Functions used to scale the image:
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 } }