Solution screenshots:
------------------------------------Implementation-----------------------------:
Core Data: Photo.isFavorite:
-
First thing first, I added
isFavorite
Boolean attribute forPhoto
entity in Photorama Core Data :
-
Second, I deleted
Photo+CoreDataClass.swift
&Photo+CoreDataProperties.swift
files and regenerated files by selecting Photo entity and going to Editor → Create NSManagedObject Subclass… Now that we have our Core Data taking care of we can move on to implementing code and the Interface.
Every photo must be not favorite by default:
PhotoStore.swift
→processPhotosRequest(data, error, completion) -> Void)
:
Now we can implement logic for favoriting and unfavoriting a Photo:
-
Adding
RightBarButtonItem
as a favorite/unfavorite button. I added aprivate func displayFavorite()
inPhotoInfoViewController
to do this (you might get an error typing, we will fix the error next):
-
Which adds the
RightBarButtonItem
with star filled background image if the photo is a favorite photo and regular (unfilled) star background image otherwise. -
Fixing the error. We have an error because action function for button is missing, adding
favoritePhoto()
:
Upon clicking the button this function gets fired. And it favorites/unfavorites the photo(photo.isFavorite = !photo.isFavorite
). Then saving the changes in Core Data in the next line (if we don’t save, changes won’t persist when closing the app and relaunching it). And finally updating background picture in the last line. -
After calling our newly added funcion from
viewDidLoad()
inPhotoInfoViewController.swift
this is the result (not favorite and favorite photos):
Now we can add a
UISegmentedControl
to switch the display between Regular photos and Favorite photos:
-
Interface:
-
Adding an outlet in
PhotosViewController.swift
and hook it up withUISegmentedControl
in the interface:
@IBOutlet private var favoriteSegment: UISegmentedControl!
-
Next in
PhotosViewController.swift
we add a Action func forUISegmentedControl
and hook it in the interface:
Index 0 inUISegmentedControl
is regular photos and index 1 is favorite photos. By default we want to display regular photos and segment will select index 0 by default.
Each time Segment changes value we update data source for collection view. So we switch over segments selected index and callupdateDataSource()
func.
Update data source:
-
We add highlighted code into
updateDataSource()
func:
Adding a conditional if we are displaying Photos, we want to display all of them (regular & favorite), so we give photo data source all the photos. If we are displaying only favorites, we filter photos that arephoto.isFavorite
and supply a new filtered array of favorite photos to data source.
At this point if you run the app, add make few photos favorite and select segment control for favorite photos you will see them displayed. But what if you have 0 favorite photos and and switch over the segment for favorite photos ? You will get a blank Collection View:
We are fixing this next -
Adding
UILabel
for “No Favorite Photo” prompt:
I added a UILabel in Interface and set to be horizontally and vertically in container. And hooked it’s outlet inPhotosViewController
:@IBOutlet private var noFavePhotosLabel: UILabel!
:
Then added the highlited code toupdateDataSource()
func:
If there are 0 favorite photos we want the label text to be “No Favorite Photos” otherwise empty string:
When having 1 or more favorite photos:
When having 0 favorite photos:
-
We are done, but there are some edge cases, so we are not done yet, we will fix that next:
Navigating between
ViewControllers
will result in inconsistent data display:
-
When having multiple favorite photos, and viewing them in Favorite-Photos state using Segment Control, and tapping on a photo, it would take you to
PhotoInfoViewController
where you can still unfavorite them. But when clicking back and navigating back to PhotosViewController which in Favorite-Photos state would still display the photo we just unfavorite:
-
To fix this we want to update the UI whenever we navigate between
PhotoInfoViewController.swift
→PhotosViewController.swift
. We do that by addingviewWillAppear(_ animated: Bool)
func inPhotosViewController.swift
. Call it’s super view and updateDataSource again:
Now that problem is fixed. Also this would still work in a scenario where you are in Favorite-Photos state and have your last favorite photo, you tap on it to go toPhotoInfoViewController
, unfavorite the photo and navigate back. Not only photo has been removed from favorite photos and not being displayed, but also you get a prompt saying “No Favorite Photos”:
Happy coding. Feel free to ask questions, suggest improvements or remind me if i missed any scenarios.