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"
}