Downloading and Displaying the Image Data

You have done a lot already in this chapter: You have successfully interacted with the Flickr API via a web service request, and you have parsed the incoming JSON data into Photo model objects. Unfortunately, you have nothing to show for it except some log messages in the console.

In this section, you will use the URL returned from the web service request to download the image data. Then you will create an instance of UIImage from that data, and, finally, you will display the first image returned from the request in a UIImageView. (In the next chapter, you will display all of the images that are returned in a grid layout driven by a UICollectionView.)

The first step is downloading the image data. This process will be very similar to the web service request to download the photos’ JSON data.

Open PhotoStore.swift, import UIKit, and add an enumeration to the top of the file that represents the result of downloading the image. This enumeration will follow the same pattern as the PhotosResult enumeration, taking advantage of associated values. You will also create an Error to represent photo errors.

import Foundation
import UIKit

enum ImageResult {
    case success(UIImage)
    case failure(Error)
}

enum PhotoError: Error {
    case imageCreationError
}

enum PhotosResult {
    case success([Photo])
    case failure(Error)
}

If the download is successful, the success case will have the UIImage associated with it. If there is an error, the failure case will have the Error associated with it.

Now, in the same file, implement a method to download the image data. Like the fetchInterestingPhotos(completion:) method, this new method will take in a completion closure that will return an instance of ImageResult.

func fetchImage(for photo: Photo, completion: @escaping (ImageResult) -> Void) {

    let photoURL = photo.remoteURL
    let request = URLRequest(url: photoURL)

    let task = session.dataTask(with: request) {
        (data, response, error) -> Void in

    }
    task.resume()
}

Now implement a method that processes the data from the web service request into an image, if possible.

private func processImageRequest(data: Data?, error: Error?) -> ImageResult {
    guard
        let imageData = data,
        let image = UIImage(data: imageData) else {

            // Couldn't create an image
            if data == nil {
                return .failure(error!)
            } else {
                return .failure(PhotoError.imageCreationError)
            }
    }

    return .success(image)
}

Still in PhotoStore.swift, update fetchImage(for:completion:) to use this new method.

func fetchImage(for photo: Photo, completion: @escaping (ImageResult) -> Void) {

    let photoURL = photo.remoteURL
    let request = URLRequest(url: photoURL)

    let task = session.dataTask(with: request) {
        (data, response, error) -> Void in

        let result = self.processImageRequest(data: data, error: error)
        completion(result)
    }
    task.resume()
}

To test this code, you will download the image data for the first photo that is returned from the interesting photos request and display it on the image view.

Open PhotosViewController.swift and add a new method that will fetch the image and display it on the image view.

func updateImageView(for photo: Photo) {
    store.fetchImage(for: photo) {
        (imageResult) -> Void in

        switch imageResult {
        case let .success(image):
            self.imageView.image = image
        case let .failure(error):
            print("Error downloading image: (error)")
        }
    }
}

Now update viewDidLoad() to use this new method.

override func viewDidLoad() {
    super.viewDidLoad()

    store.fetchInterestingPhotos {
        (photosResult) -> Void in

        switch photosResult {
        case let .success(photos):
            print("Successfully found (photos.count) photos.")
            if let firstPhoto = photos.first {
                self.updateImageView(for: firstPhoto)
            }
        case let .failure(error):
            print("Error fetching interesting photos: (error)")
        }
    }
}

Although you could build and run the application at this point, the image may or may not appear in the image view when the web service request finishes. Why? The code that updates the image view is not being run on the main thread.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset