Silver Challenge Solution with UISegmentController

The Silver Challenge requirements state clearly that the app must be extended to switch between interesting photos and recent photos. A user must intuitively understand what is shown to him. This is a perfect job for a UISwitchController which was added to the Storyboard with 2 segments ‘Interesting’ and ‘Recent’ and hooked up to the PhotosViewController with a photoSwitch outlet (post here only the source code relevant to the solution):

class PhotosViewController: UIViewController {

...
@IBOutlet weak var photoSwitch: UISegmentedControl!
...

override func viewDidLoad() {
    super.viewDidLoad()
    loadPhotos()
    photoSwitch.addTarget(self, action: #selector(loadPhotos), for: .valueChanged)
}

...

@objc private func loadPhotos() {
    let photoType: PhotoType
    switch photoSwitch.selectedSegmentIndex {
    case 0:
        photoType = .interesting
        print("$$$$$$$ Interesting $$$$$$$")
    case 1:
        photoType = .recent
        print("@@@@@@@ Recent @@@@@@@")
    default:
        preconditionFailure("Code must not get here - uselected photo type")
    }
    
    store.fetchPhotos(of: photoType) {
        (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)")
        }
    }
}

}

The photoSwitch was added a target-action pair to call loadPhotos() method whenever its value is changed. This method is also called when the view is loaded to fetch the first photo. Nothing new is here as it was extracted from the viewDidLoad() except the switch statement to set an internal photoType variable which is then passed as an argument to fetchPhotos(of type: PhotoType, completion: @escaping (PhotosResult) -> Void) method of the PhotoStore instance.

In the PhotoStore struct the signature of the fetchInterstingPhotos(completion: @escaping (PhotosResult) -> Void) method was changed to fetchPhotos(of type: PhotoType, completion: @escaping (PhotosResult) -> Void) in order to use the new argument type to construct the request URL depending on the user’s choice of photo type:

struct PhotoStore {

...
func fetchPhotos(of type: PhotoType, completion: @escaping (PhotosResult) -> Void) {
    let url: URL
    if type == .interesting {
        url = FlickrAPI.interestingPhotosURL
    } else {
        url = FlickrAPI.recentPhotosURL
    }
    ...
}
    ...

}

Of course, the Phototype enum was extended with a new type:

enum PhotoType {
    case interesting
    case recent
}

Then FlickrAPI struct was added a new recentPhotosURL property:

struct FlickrAPI {
    ...
    static var recentPhotosURL: URL {
        return flickrURL(method: .recentPhotos, parameters: ["extras": "url_h,date_taken"])
    }
   ...
}

And finally, the Method enum modified to keep the recentPhotos URL:

enum Method: String {
    case interestingPhotos = "flickr.interestingness.getList"
    case recentPhotos = "flickr.photos.getRecent"
}