 <p>Skip to <strong>Processing the Image</strong> to find out how to convert <code>UIImage</code> to <code>NSData</code> (which is what Core Data uses)</p> <p>Or download from <a href="https://github.com/romainmenke/SimpleCam" rel="nofollow noreferrer">github</a></p> <p><strong>Core Data Setup:</strong></p> <p>Set up two entities : Full Resolution and Thumbnail. Full Resolutions is to store the original image. Thumbnail to store a smaller version to be used inside the app. You might use a smaller version in a <code>UICollectionView</code> overview for example.</p> <p>Images are stored as <code>Binary Data</code> in <code>Core Data</code>. The corresponding type in <code>Foundation</code> is <code>NSData</code>. Convert back to <code>UIImage</code> with <code>UIImage(data: newImageData)</code></p> <p><a href="https://i.stack.imgur.com/HJkRs.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/HJkRs.png" alt="enter image description here"></a></p> <hr> <p><a href="https://i.stack.imgur.com/WU38e.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/WU38e.png" alt="enter image description here"></a></p> <hr> <p>Check the <strong>Allows External Storage</strong> box for the Binary Data fields. This will automatically save the images in the file system en reference them in Core Data</p> <p><a href="https://i.stack.imgur.com/ctgDN.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/ctgDN.png" alt="enter image description here"></a></p> <p>Connect the two entities, creating a one to one relationship between the two. </p> <p><a href="https://i.stack.imgur.com/JXxf2.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/JXxf2.png" alt="enter image description here"></a></p> <p>Go to <strong>Editor</strong> en select Create <strong>NSManagedObjectSubclass</strong>. This will generate files with Classes representing your Managed Object SubClasses. These will appear in your project file structure.</p> <p><a href="https://i.stack.imgur.com/603At.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/603At.png" alt="enter image description here"></a></p> <hr> <p><strong>Basic ViewController Setup:</strong></p> <p>Import the following :</p> <pre><code>import UIKit import CoreData </code></pre> <hr> <ul> <li>Setup two <code>UIButtons</code> and an <code>UIImageView</code> in the Interface Builder</li> <li>Create two dispatch queues, one for CoreData and one for UIImage conversions</li> </ul> <hr> <pre><code>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) -&gt; Void in if let thumbnailData = images?.last?.thumbnail?.imageData { let image = UIImage(data: thumbnailData) self.imageView.image = image } } } } </code></pre> <hr> <p>This function sets a value to <code>managedContext</code> on the correct thread. Since CoreData needs all operations in one <code>NSManagedObjectContext</code> to happen in the same thread.</p> <pre><code>extension ViewController { func coreDataSetup() { dispatch_sync(saveQueue) { self.managedContext = AppDelegate().managedObjectContext } } } </code></pre> <hr> <p>Extend the <code>UIViewController</code> so it conforms to <code>UIImagePickerControllerDelegate</code> and <code>UINavigationControllerDelegate</code> These are needed for the <code>UIImagePickerController</code>.</p> <p>Create a setup function and also create the delegate function <code>imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage, editingInfo: [String : AnyObject]?)</code></p> <pre><code>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) } } </code></pre> <p>Immediately dismiss the <code>UIImagePickerController</code>, else the app will appear to freeze.</p> <hr> <p><strong>Processing the Image:</strong></p> <p>Call this function inside <code>imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage, editingInfo: [String : AnyObject]?)</code>. </p> <ul> <li><p>First get the current date with <code>timeIntervalSince1970</code>. This returns an <code>NSTimerInterval</code> in seconds. This converts nicely to a <code>Double</code>. It will serve as a unique id for the images and as a way to sort them.</p></li> <li><p>Now is a good time to move to the separate queue and free up the main queue. I used <code>dispatch_async(convertQueue)</code> first to do the heavy lifting on a separate thread.</p></li> <li><p>Then you need to convert the <code>UIImage</code> to <code>NSData</code> this is done with <code>UIImageJPEGRepresentation(image, 1)</code>. The <code>1</code> represents the quality where <code>1</code> is the highest and <code>0</code> is the lowest. It returns an optional so I used optional binding.</p></li> <li><p>Scale the image to a desired thumbnail size and also convert to <code>NSData</code>.</p></li> </ul> <p><strong>Code:</strong></p> <pre><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) } } } </code></pre> <p>This function does the actual saving.</p> <ul> <li>Go the the CoreData thread with <code>dispatch_barrier_sync(saveQueue)</code></li> <li>First insert a new FullRes and a new Thumbnail object into the Managed Object Context.</li> <li>Set the values</li> <li>Set the relationship between FullRes and Thumbnail</li> <li>Use <code>do try catch</code> to attempt a save</li> <li>Refresh the Managed Object Context to free up memory</li> </ul> <p>By using <code>dispatch_barrier_sync(saveQueue)</code> we are sure that we can safely store a new image and that new saves or loads will wait until this is finished.</p> <p><strong>Code:</strong></p> <pre><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() } } } </code></pre> <p><strong>To load an image :</strong></p> <pre><code>extension ViewController { func loadImages(fetched:(images:[FullRes]?) -&gt; 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 } } } } </code></pre> <p><strong>The functions used to scale the image:</strong></p> <pre><code>extension CGSize { func resizeFill(toSize: CGSize) -&gt; CGSize { let scale : CGFloat = (self.height / self.width) &lt; (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) -&gt; 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 } } </code></pre>