How to Programmatically Save and Load UIImage Files in The Document Directory with Swift

Interacting with System directories in your device is often a common task and comes in handy when you need to store some type of data for later use, without the need to fetch from the server or elsewhere.

In this tutorial, you gonna build a quick app that takes pictures using the UIImagePickerController class and saves them inside a folder that you will create in the Document directory of your device. The app will later load those images and populate them in a table view.

What you will learn:

  • How to use the UIImagePickerController class for fast images browsing.
  • How to programmatically fetch the Document directory.
  • How to programmatically make a new folder.
  • How to save and load files from a directory with a given path.
  • Without further ado, let’s build this!

    Open up Xcode, select “File\New\Project” from the menu, then choose the Single View Application template. Name the project “ImagePicker” and save it.

    Create a new project in Xcode

    First thing, we want to use a UITableViewController instead of the default UIViewController created by default in the storyboard scene. So head over to the Main.storyboard file, select the View Controller Scene from the Document Outline view and press the delete key to completely remove it.

    Remove a view controller from storyboard scene

    Next, drag a UITableViewController object from the Object library to the canvas, then follow the steps below:

    – Select the Table View Cell from the Document Outline view, then switch to the Attributes inspector and set the Identifier property to “CellID”.
    – Make sure the Table View Controller is selected, then switch to the Attributes inspector and check the Is Initial View Controller check box.
    – Select “Editor\Embed In\Navigation Controller” from the menu to add a navigation controller container to the table view controller.

    Also, select the ViewController.swift file from the Project navigator view to load it in the editor. Now, change the class declaration to the following:

    class ViewController: UITableViewController {
    

    Move back to the storyboard, select the Table View Controller, then set the Class property to “ViewController” in the Identity inspector.

    Set the Class property in the Identity inspector in Xcode

    To finish up with the UI, let’s just add a button to launch the UIImagePickerController API for photos browsing. To do so, drag a UIBarButtonItem from the Object library and place it to the right of the navigation bar of the Table View Controller. Select the newly added bar button, switch to the Attributes inspector and choose the Camera attribute for System Item property.

    Change the System Item property of UIBarButtonItem in Xcode.

    You are set with the UI, now time for some code 🙂

    Switch to the Assistant editor and make sure the ViewController.swift file is loaded along with the storyboard file. Next, ctrl click on the camera bar button and drag a line to the code.

    hook up bar button item to the code

    Change the Connection type to Action and name it “choosePhoto”, then hit the Connect button to hook up the action method to the button.

    Define action method from within the Assistant editor in Xcode

    Switch back to the Standard editor and select the ViewController.swift file from the Project navigator view to load it in the editor.

    Let’s start by declaring some vars, place the following declarations just after the class name:

    var imagesDirectoryPath:String!
    var images:[UIImage]!
    var titles:[String]!
    

    The app will fetch some pictures using the UIImagePickerController, it will then save those images, precisely ,in a folder inside the Document directory.

    The imagesDirectoryPath variable will handle a reference to the images folder inside the Document directory.

    The images and titles arrays are just where will all images be saved along with their corresponding names.

    Great, now locate the choosePhoto action method and implement the following code inside:

    let imagePicker = UIImagePickerController()
    presentViewController(imagePicker, animated: true, completion: nil)
    imagePicker.delegate = self
    

    This will just initialise a UIImagePickerController instance and present it modally to the screen in order to pick an image from the photo library in your device. The image picker source type is set to photo library by default, good for you as you only want to deal with images here.

    Did you get the following compiling error?

    Cannot assign value of type ViewController to type protocol?
    

    Well, setting the view controller as the delegate of the UIImagePickerController require the class to conform to both the UIImagePickerControllerDelegate and the UINavigationControllerDelegate protocols.

    Let’s fix this right away, change the class declaration to the following:

    class ViewController: UITableViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
    

    Cool, now let’s add the folder in which you gonna save all images. Remember, this folder will be created inside the Document directory. The best place and time to create this folder is when the screen first load.

    Implement the code below inside the viewDidLoad method:

    images = []
    
    let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
    // Get the Document directory path
    let documentDirectorPath:String = paths[0]
    // Create a new path for the new images folder
    imagesDirectoryPath = documentDirectorPath.stringByAppendingString("/ImagePicker")
    var objcBool:ObjCBool = true
    let isExist = NSFileManager.defaultManager().fileExistsAtPath(imagesDirectoryPath, isDirectory: &objcBool)
    // If the folder with the given path doesn't exist already, create it
    if isExist == false{
      do{
          try NSFileManager.defaultManager().createDirectoryAtPath(imagesDirectoryPath, withIntermediateDirectories: true, attributes: nil)
        }catch{
          print("Something went wrong while creating a new folder")
        }
    }
    

    The code above will first initialise the images array, then it will create a new path for the new folder under the Document directory. On my simulator, the new path is something like this:

    /Users/malek/Library/Developer/CoreSimulator/Devices/8ER9F428-AF1D-4538-9498-DB7B1B15C441/data/Containers/Data/Application/E43C7E1E-792D-4E59-B410-38019B043773/Documents/ImagePicker
    

    Before you create the folder, the code above will check whether it does already exist on that path. If not, it will create a new folder with the same path.

    So far so good, now, once you choose a picture, you want to save it to the ImagePicker directory. For such purpose, you gonna use the imagePickerController:didFinishPickingImage: protocol method. This is the method that will be called on the delegate and provide the selected image to be saved.

    Before the closing bracket of the class, copy the following code:

    func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage, editingInfo: [String : AnyObject]?) {
            
    // Save image to Document directory
    var imagePath = NSDate().description
    imagePath = imagePath.stringByReplacingOccurrencesOfString(" ", withString: "")
    imagePath = imagesDirectoryPath.stringByAppendingString("/\(imagePath).png")
    let data = UIImagePNGRepresentation(image)
    let success = NSFileManager.defaultManager().createFileAtPath(imagePath, contents: data, attributes: nil)
    dismissViewControllerAnimated(true) { () -> Void in
        self.refreshTable()
    }
    }
    

    The code above will simply use the current date and time as the image name, I think this is the best way to prevent redundant images and to avoid conflicting names inside the ImagePicker folder. Then, you simply created a new path for the image inside the folder and saved it with a PNG extension. Last but not least, you dismissed the current picker image screen and reloaded the table view to reflect the new saved image.

    Next, let’s implement the refreshTable method. Implement the following method code inside the class:

    func refreshTable(){
            do{
                images.removeAll()
                titles = try NSFileManager.defaultManager().contentsOfDirectoryAtPath(imagesDirectoryPath)
                for image in titles{
                    let data = NSFileManager.defaultManager().contentsAtPath(imagesDirectoryPath.stringByAppendingString("/\(image)"))
                    let image = UIImage(data: data!)
                    images.append(image!)
                }
            self.tableView.reloadData()
            }catch{
                print("Error")
            }
    }
    

    The method above will first fetch all the content inside the ImagePicker folder. The contentsOfDirectoryAtPath method will return an array of strings reflecting the files’ names. Then, you just loop over the images, extract them as NSData types, transform to UIImage types then store to the images array.

    You embedded the contentsOfDirectoryAtPath API inside a do-catch block to handle any potential errors it may throw.

    You are almost done, let’s implement the UITableView data source protocol methods to show your selected photos along with their names.

    Before the class closing bracket, place the following code:

        override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
            let cell:UITableViewCell! = tableView.dequeueReusableCellWithIdentifier("CellID")
            cell?.imageView?.image = images[indexPath.row]
            cell.textLabel?.text = titles[indexPath.row]
            return cell
        }
        override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return images.count
        }
    

    Nothing fancy here, the images and titles arrays, filled previously, are used to get the current image along with its title. Remember, the CellID used above to dequeue a cell from the table view is the same ID you set in the storyboard for the custom cell.

    That’s it folks, run the project and enjoy your work 🙂

    As usual, you can download the final project here.

    Feel free to leave a comment in the discussion below, I’d love to hear from you!

    Malek
    iOS developer with over than 11 years of extensive experience working on several projects with different sized startups and corporates.

    1 Comment

    1. Hi malek, can you please tell what is the safe way to download the file, Documents directory is not safe, & yes i have a text file of 10 MB is there any way to encrypt the file & save it to ios ? – Thanks

    Comments are closed.