Note that this solution is based on solution for Ch 20 Silver Challenge: Fetch Recent Photos from Flickr.
Photorama.xcdatamodeld - Add a new attribute with name “isFavorite” of type “Boolean” to the Photo entity.
// TagDataSource.swift
class TagDataSource: NSObject, UITableViewDataSource {
...
func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return section == 1 ? " " : nil
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 1 {
return 1 // The Favorite "Tag"
}
return tags.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "UITableViewCell", for: indexPath)
if indexPath.section == 1 {
cell.textLabel?.text = "Favorite"
cell.textLabel?.font = UIFont.boldSystemFont(ofSize: 17)
return cell
}
let tag = tags[indexPath.row]
cell.textLabel?.text = tag.name
return cell
}
}
// TagsViewController.swift
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.section == 1 {
photo.isFavorite = !photo.isFavorite
try? store.persistentContainer.viewContext.save()
tableView.reloadRows(at: [indexPath], with: .automatic)
return
}
...
}
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
if indexPath.section == 1 {
cell.accessoryType = photo.isFavorite ? .checkmark : .none
return
}
...
}
// PhotoStore.swift
class PhotoStore {
...
func fetchFavoritePhotos(completion: @escaping (PhotosResult) -> Void) {
let fetchRequest: NSFetchRequest<Photo> = Photo.fetchRequest()
let sortByDateTaken = NSSortDescriptor(key: #keyPath(Photo.dateTaken), ascending: false)
fetchRequest.sortDescriptors = [sortByDateTaken]
let predicate = NSPredicate(format: "(%K == TRUE)", #keyPath(Photo.isFavorite))
fetchRequest.predicate = predicate
let viewContext = persistentContainer.viewContext
viewContext.perform {
do {
let favoritePhotos = try viewContext.fetch(fetchRequest)
completion(.success(favoritePhotos))
} catch {
completion(.failure(error))
}
}
}
}
// PhotosViewController.swift
class PhotosViewController: UIViewController {
...
override func viewDidLoad() {
super.viewDidLoad()
let segmentedControl = UISegmentedControl(items: ["Interesting", "Recent", "Favorite"])
segmentedControl.addTarget(self, action: #selector(selectMethod(_:)), for: .valueChanged)
navigationItem.titleView = segmentedControl
collectionView.dataSource = photoDataSource
collectionView.delegate = self
}
@objc func selectMethod(_ sender: UISegmentedControl) {
sender.isEnabled = false
let method: Method
switch sender.selectedSegmentIndex {
case 0:
method = .interestingPhotos
case 1:
method = .recentPhotos
default:
updateDataSourceForFavoritePhotos()
DispatchQueue.main.async {
sender.isEnabled = true
}
return
}
updateDataSource()
store.fetchPhotos(for: method) { (photosResult) -> Void in
DispatchQueue.main.async {
sender.isEnabled = true
}
self.updateDataSource()
}
}
private func updateDataSourceForFavoritePhotos() {
store.fetchFavoritePhotos { (photosResult) in
switch photosResult {
case let .success(photos):
self.photoDataSource.photos = photos
case .failure:
self.photoDataSource.photos.removeAll()
}
self.collectionView.reloadSections(IndexSet(integer: 0))
}
}
private func updateDataSource() {
store.fetchAllPhotos { (photosResult) in
switch photosResult {
case let .success(photos):
self.photoDataSource.photos = photos
case .failure:
self.photoDataSource.photos.removeAll()
}
self.collectionView.reloadSections(IndexSet(integer: 0))
}
}
}