Saving reviews was pretty simple and there is essentially no difference in saving photos. Our code will be pretty similar to what we did with reviews. Open the PhotoFilterViewController, delete everything inside the checkSavedPhoto() method, and update it with the following:
func checkSavedPhoto() {
if let img = self.imgExample.image {
var item = RestaurantPhotoItem()
item.photo = generate(image: img, ratio: CGFloat(102))
item.date = NSDate() as Date
item.restaurantID = selectedRestaurantID
let manager = CoreDataManager()
manager.addPhoto(item)
}
}
This method will make sure that we have an image and then save it to Core Data with its restaurant ID. We need to add a method for when Save is tapped. Add the following method inside the private extension:
@IBAction func onSaveTapped(_ sender: AnyObject) {
DispatchQueue.main.async {
self.checkSavedPhoto()
}
}
Now, when a user taps the Save button, this will make sure that an image is saved; if so, it will save the data to Core Data. Before we can save, we need to pass the restaurant identifier to the PhotoFilterViewController.swift.
- Open RestaurantDetail.storyboard and select the segue we are using to go to the Photo Filter View.
- In the Attributes inspector of the Utilities panel, update Identifier under Storyboard Segue to say showPhotoFilter. Then, hit Enter.
- Finally, open the Segue.swift file in the Misc folder under the Common folder and verify that the following case statement is included; if not, add it:
case showPhotoFilter
- Inside the RestaurantDetailViewController.swift, update your prepare method with the following:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let identifier = segue.identifier {
switch identifier {
case Segue.showReview.rawValue:
showReview(segue: segue)
case Segue.showPhotoFilter.rawValue:
showPhotoFilter(segue: segue)
default:
print("Segue not added")
}
}
}
- Next, add the following method after the showReview() method inside your private method:
func showPhotoFilter(segue:UIStoryboardSegue) {
guard let navController = segue.destination as? UINavigationController,
let viewController = navController.topViewController as? PhotoFilterViewController else {
return
}
viewController.selectedRestaurantID = selectedRestaurant?.restaurantID
}
We are passing the restaurant identifier to our photos and we now have our photos saved in Core Data. After you save a photo, you are brought back to the restaurant detail view but next we need to display the photos in our Detail section.
We are missing one last thing. The photo review and review sections need to pull data from the database for it to be displayed. We need to create a class for each one, so let's start by adding this class now:
- Create a new folder called Reviews.
- Now, right-click the folder and select New File.
- Inside the Choose a template for your new file screen, select iOS at the top and then Cocoa Touch Class. Then, hit Next.
- In the options screen that appears, add the following:
New file:
-
- Class: ReviewsViewController
- Subclass: UIViewController
- Also create XIB: Unchecked
- Language: Swift
- Hit Next and then Create. When the file opens, replace everything with the following code:
import UIKit
class ReviewsViewController: UIViewController {
@IBOutlet weak var collectionView: UICollectionView!
var selectedRestaurantID:Int?
let manager = CoreDataManager()
var data: [ReviewItem] = []
override func viewDidLoad() {
super.viewDidLoad()
initialize()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
setupDefaults()
}
}
- Next, let's add our private extension by adding the following:
private extension ReviewsViewController {
func initialize() {
setupCollectionView()
}
func setupDefaults() {
checkReviews()
}
func setupCollectionView() {
let flow = UICollectionViewFlowLayout()
flow.sectionInset = UIEdgeInsets(top: 7, left: 7, bottom: 7, right: 7)
flow.minimumInteritemSpacing = 0
flow.minimumLineSpacing = 7
flow.scrollDirection = .horizontal
collectionView?.collectionViewLayout = flow
}
func checkReviews() {
let viewController = self.parent as? RestaurantDetailViewController
if let id = viewController?.selectedRestaurant?.restaurantID {
if data.count > 0 { data.removeAll() }
data = manager.fetchReviews(by: id)
if data.count > 0 {
collectionView.backgroundView = nil
}
else {
let view = NoDataView(frame: CGRect(x: 0, y: 0, width: collectionView.frame.width, height: collectionView.frame.height))
view.set(title: "Reviews")
view.set(desc: "There are currently no reviews")
collectionView.backgroundView = view
}
collectionView.reloadData()
}
}
}
We are doing the basic setup that we did before. Our checkReviews() method is a bit different, because we are first checking to see if there are any reviews at all. If there are not, we display a message that says There are currently no reviews. If there are, we do not display anything.
- Next, let's add our Collection View extensions by adding the following to our data source:
extension ReviewsViewController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return data.count
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
return collectionView.dequeueReusableCell(withReuseIdentifier: "reviewCell", for: indexPath)
}
}
- Next, let's add our Collection View extensions by adding the following to our layout:
extension ReviewsViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath:IndexPath) -> CGSize {
if data.count == 1 {
let width = collectionView.frame.size.width - 14
return CGSize(width: width, height: 200)
}
else {
let width = collectionView.frame.size.width - 21
return CGSize(width: width, height: 200)
}
}
}
Next, for our Collection View to work, we need to create our cell and an extension of this class:

- Right-click the Review folder and select New File.
- Inside the Choose a template for your new file screen, select iOS at the top and then Cocoa Touch Class. Then, hit Next.
- In the options screen that appears, add the following:
New file:
-
- Class: ReviewCell
- Subclass: UICollectionViewCell
- Also create XIB: Unchecked
- Language: Swift
- Click Next and then Create.
- In this new file, add the following code:
@IBOutlet weak var lblTitle: UILabel!
@IBOutlet weak var lblDate: UILabel!
@IBOutlet weak var lblName: UILabel!
@IBOutlet weak var lblReview: UILabel!
@IBOutlet weak var ratingView: RatingView!
- Save the file and open up RestaurantDetail.storyboard.
- Locate the Container that we created for Reviews and select the cell inside the Collection View. Select the View Controller and in the Identity inspector and under Custom Class set Class to ReviewsViewController.
- Then hit Enter.
- Now, in the Utilities panel, under the Size inspector, update the Size to Custom.
- Next, set Width to 350 and Height to 200.
- Under the Attributes inspector, set the Identifier to reviewCell and the background color to #F2F2F2. You can add this color to your Color set.
- Then under Identity inspector, update the class to ReviewCell.
- Select the Collection View, and in the Identity inspector click and drag from dataSource and delegate to the View Controller.