To start, we are only going to concern ourselves with temporarily storing our pictures in memory. To do this, we can add an image array as a property of our view controller:
class ViewController: UIViewController { var photos = [UIImage]() // ... }
As we saw in the image picker delegate method, UIKit provides a class UIImage
that can represent images. Our photos
property can store an array of these instances. This means that the first step for us is to add new images to our property when the callback is called:
func imagePickerController( picker: UIImagePickerController, didFinishPickingImage image: UIImage!, editingInfo: [NSObject : AnyObject]! ) { self.photos.append(image) self.dismissViewControllerAnimated(true, completion: nil) }
Now every time the user takes or picks a new photo, we add it to our list, which stores all of the images in memory. However, this isn't quite enough, we also want to require a label for each photo.
To support this feature, let's create a new structure called Photo
that has an image and label property. At this point, I would create three groups in the LearningCamera
folder: Model, View, and Controller by right-clicking on the LearningCamera
folder and choosing New Group. I would move ViewController.swift
into the Controller group and then create a new Photo.swift
file by right-clicking on the Model group and selecting New Fileā¦. Just a plain Swift File is fine.
You should define your photo structure in that file:
import UIKit struct Photo { let image: UIImage let label: String }
We have to import UIKit because that is what defines UIImage. The rest of our structure is straightforward as it just defines our two desired properties. The default initializer will be fine for now.
Now, we can return to our ViewController.swift
file and update our photos
property to be of the type Photo
instead of UIImage
:
var images = [Photo]()
This now creates a new problem for us. How do we ask the user for the label for the image? Let's do that in a standard alert. To display an alert, UIKit has a class called UIAlertController
. To use this, we will have to rework our function some. UIKit does not allow you to present more than one view controller from the same view controller at the same time. This means that we have to dismiss the photo picker and wait for that to complete before displaying our alert:
self.dismissViewControllerAnimated(true) { // Ask User for Label let alertController = UIAlertController( title: "Photo Label", message: "How would you like to label your photo?", preferredStyle: .Alert ) alertController.addTextFieldWithConfigurationHandler() { textField in let saveAction = UIAlertAction( title: "Save", style: .Default ) { action in let label = textField.text ?? "" let photo = Photo(image: image, label: label) self.photos.append(photo) } alertController.addAction(saveAction) } self.presentViewController( alertController, animated: true, completion: nil ) }
Lets break down this code, as it is somewhat complex. To start, we are using the trailing closure syntax for the dismissViewControllerAnimated:completion:
method. This closure is called once the view controller has finished animating off the screen.
Next, we are creating an alert controller with a title, message, and Alert
as its style. Before we can display the alert controller, we have to configure it with a text field and a save action. We start by adding the text field and use the trailing closure again on addTextFieldWithConfigurationHandler:
. This closure is called to give us an opportunity to configure the text field. We are OK with the defaults but we are going to want to know the text contained in the text field when saving so we can create our save action directly within this alert and save ourselves the hassle of getting a reference to it later.
Each action of an alert must be of the type UIAlertAction
. In this case, we create one with the title Save
with the default style. The last parameter of the UIAlertAction
initializer is a closure that will be called when the user chooses that action. Again, we use the trailing closure syntax.
Inside that callback, we get the text from the text field and use that, along with our image, to create a new Photo
instance and add it to our photos
array.
Finally, we have to add our save action to the alert controller and then display the alert controller.
Now if you run the app, it will ask you for a label for each photo after it is chosen but it still won't appear to be showing it because we are not displaying the saved photos yet. That is our next task.