In this app, I have three view controllers:
- ContentsVC
- ChapterVC
- RecipeVC
When a user taps a Chapter, the screen segues to the ChapterViewController. The collection of Chapters then displays in the left-hand column, and a Table of Recipes will appear in the body of the screen, and the label of the chapter will appear in the header.
The intention is that when the user taps a recipe the screen segues to the RecipeViewController. The collection of Chapters is not displayed, and the Table of Recipes will now appear in the left-hand column, and the Recipe details will display in the body of the screen. The label of the chapter will appear atop the Table of Recipes, and the label of the Recipe will appear in the Header.
UPDATED
I can’t figure out how to handle the selectedChapterIndex across VCs. The problem appears to be that in the segue from the ContVC
let chapter = chapters[selectedChapterIndex]
is getting the initialised index from
var selectedChapterIndex:Int = 0
but not from the UICollectionViewDelegate method didSelectItemAt
selectedChapterIndex = indexPath.row
So I am confounded as to how to get the segue to pick up the index from didSelectItemAt
I have pasted the code of the ContentsViewController below.
Alternately I have a repo in GitHub, so if you would like to help, let me know your GitHub username and I can add you as a collaborator
//
// ContentsViewController.swift
// CookAlpha
//
// Created by Lachlan McKerrow on 20/12/19.
// Copyright © 2019 Lachlan McKerrow. All rights reserved.
//
import UIKit
class ContentsViewController: UIViewController {
// 1g Create the property for the CookbookModel
var model = CookbookModel()
// 1h Declare a cookbook property so we can store a reference to chapters and recipes that come back, and initialise it to an empty array
var cookbook = [Cookbook]()
// 4c Declare a chapter property so we can store a reference to chapters that come back, and initialise it to an empty array
var chapters = [Chapter]()
// 4a Drag in the Chapters View's Collection View outlet
@IBOutlet weak var chapterCollection: UICollectionView!
// 7b Store the index of the default chapter, and initialize it to 0
var selectedChapterIndex:Int = 0
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
// 4b Conform to the collectionView protocols
chapterCollection.delegate = self
chapterCollection.dataSource = self
// 1m Assign the SVC as delegate
model.delegate = self
// 1i Call getCookbook from the CookbookModel
model.getCookbook()
}
// 11c Before the segue occurs, this gives us access to the destination ChapVC so we can set properties
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// 11d Detect the index path of the chapter which the user tapped on for Collection View
let indexPath = chapterCollection.indexPathsForSelectedItems
guard indexPath != nil else {
print("User didn't select a chapter!")
return
}
// 11e Get the selected chapter. If it is not nil, then we set the item, which is unwrapped, as it has been verified that it is not nil
let chapter = chapters[selectedChapterIndex]
// 11f Get a reference to the ChapVC
let chapterVC = segue.destination as! ChapterViewController
// 11g Set the chapter properties (or URL) to be segued into ChapVC
chapterVC.selectedChapter = chapter.chapterName
chapterVC.selectedChapterIndex = chapter.chapterIndex
}
}
// 4j Add the UICollectionViewDelegate
extension ContentsViewController: UICollectionViewDelegate {
// 4k Add the didSelectItemAt Chapter Collection
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
// 11h Update the selectedChapterIndex
selectedChapterIndex = indexPath.row
// 11i Reload the chapterCollection to display recipes in the newly selected chapter
// chapterCollection.reloadData()
}
}
// 4d Add the UICollectionViewDataSource
extension ContentsViewController: UICollectionViewDataSource {
// 4e Add in the numberOfItemsInSection stub
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
// 4f Return the number of chapters
return chapters.count
}
// 4g Add in the cellForItemAt stub
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
// 4h Get the cell
// let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ChapterCell", for: indexPath)
// 5k After commenting out 4h We can now cast the following call as a ChapterCell by adding 'as! ChapterCell'
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: Constants.Views.ChapterCell, for: indexPath) as? ChapterCell
else {
fatalError("Wrong cell class dequed")
}
// 5l TEST: Get chapter that the collectionview is trying to display
let chapter = chapters[indexPath.row]
// 5m TEST: For the cell at row get the chapters
cell.displayChapter(chapter)
// 5o Add Chapter Images into the Assets, then test the app
// 4i Return that cell
return cell
}
}
// 1n Create the extension and have the ContVC conform to the CookbookModelProtocol in an extension
extension ContentsViewController: CookbookModelProtocol {
// 1o Get the sections and recipes from the CookbookModel
func cookbookRetrieved(_ cookbook: Cookbook) {
// 1p TEST (needs 1q over in CookbookModel.swift) print a statement to verify that the comms have been set up correctly
// print("Test that Cookbook comes back")
// 1r Now we are pulling back JSON feed, assign the chapters that come back to the property at 2a nee 1q in CookbookModel, which provides a reference for when we want to display the in the collection view. Here's the thing to remember: Given the block of code, "chapters" mean nothing in this block, so we must use dot notation to join "cookbook" to "chapters" in order to bring in the parsed JSON data
self.chapters = cookbook.chapters
// 4l Reload collection view chapterCollection, then run the app to see if it works :)
chapterCollection.reloadData()
}
}