A student that completes this project shows that they can:
- understand and explain what a protocol is and common scenarios for their use
- define a custom protocol, and make a class or struct conform to it
- understand and explain the purpose of UITableViewController
- use a regular UIViewController to display a UITableView
- create a custom UITableViewCell
- understand and explain the delegate pattern and why it is used
Grail Diary is an app that allows the user to track locations of interest (POIs) and useful facts about those locations.
Please use the same repository you used yesterday for Grail Diary Part 1. If you've created a PR to submit your work, you'll continue to use the same PR. New commits will automatically be added to that PR. Just submit the same link again at the end of this assignment.
- Create a new file using the Cocoa Touch Class template; call it
POIsTableViewController
and use the parent classUIViewController
- Create 2 more files in the same way;
AddPOIViewController
(subclassed fromUIViewController
) andPOIDetailViewController
(also subclassed fromUIViewController
) - Create a class subclassed from
UITableViewCell
calledPOITableViewCell
- Create a Swift file called
POI
(this is your model)
- Set the custom class for each view controller scene in the storyboard to match the names of the files you just created
- Create a
struct
calledPOI
that models 3 properties:location
,country
, andclues
; the data types areString
,String
, and an array ofString
objects
- Create an array property to store your
POI
models - Create an
IBOutlet
to link the table view to your code; wire up this outlet to the table view in the storyboard - In an extension, make this class conform to the
UITableViewDataSource
protocol - Implement the following protocol methods:
tableView(_:numberOfRowsInSection:)
andtableView(_:cellForRowAt:indexPath:)
- Wire up the
delegate
property of the tableview in the storyboard to the view controller
- Declare
IBOutlet
properties for the 5 textfields in this view; wire these up to their appropriate textfields in the storyboard - Declare a protocol above this class in the same file called
AddPOIDelegate
; declare a single function requirement calledpoiWasAdded(_ poi: POI)
- Declare a variable property called
delegate
of typeAddPOIDelegate
and make it optional - Create 2
IBAction
methods:cancelTapped(_ sender: UIBarButtonItem)
, andsaveTapped(_ sender: UIBarButtonItem)
; wire them up to their appropriate bar button items in the storyboard - Inside
cancelTapped
, simply dismiss this view as the user has indicated they want to leave this screen - Inside
saveTapped
, guard unwrap the text inside the location and country textfields, initialize aPOI
object, and then if-let unwrap the 3 clue textfields and add them to the POI if applicable - At the end of the
saveTapped
method, call the delegate method on the delegate property and pass the POI that was just created as an argument - In an extension, make the class conform to the
UITextFieldDelegate
protocol - In the storyboard, for each textfield in this view, connect the delegate property of the textfield to this class
- Implement the delegate method
textFieldShouldReturn(_:)
; unwrap the text and make sure it's not empty, thenswitch
off the textfield to determine which one called this method; change thefirstResponder
status to the appropriate textfield
- In an extension, make the class conform to the
AddPOIDelegate
protocol - Implement the delegate method
poiWasCreated(_:)
- Append the poi that was passed into the method to your array
- Dismiss the view so the modal animates offscreen
- Reload the tableview's data
- In the main class definition, implement the
prepare(for:sender:)
method (it might be commented out) - Check the identifier of the segue first; look for the identifier
AddPOIModalSegue
- If that identifier is found, use the segue object's
destination
property to grab the view controller we're transitioning to and cast it as an instance ofAddPOIViewController
; you'll need to unwrap this as the cast may not succeed - If the unwrap is successful, use the view controller you unwrapped, set its
delegate
property toself
; this ensures thePOIsTableViewController
will act on behalf of theAddPOIViewController
- Declare
IBOutlet
properties for the following cell elements:locationLabel
,countryLabel
, andcluesCountLabel
; connect them to their appropriate labels in the storyboard - Declare an optional property called
poi
of typePOI
; add adidSet
observer that calls a function namedupdateViews
- Define a private function named
updateViews
; inside, unwrappoi
and use its properties to populate the various labels with data
- Declare 3
IBOutlet
properties:locationLabel
,countryLabel
, andcluesTextView
usingUILabel
andUITextView
for the types; wire them to their appropriate subviews in the storyboard - Declare a variable property called
poi
of typePOI
- Create a private method called
updateViews
that takes no arguments - Call the above method inside
viewDidLoad
- In
updateViews
, unwrap the poi property withguard
and set the various model properties to the text of the labels and the textview; you'll have to do a little formatting to show the clues as a list in thecluesTextView
- In the
prepare(for:sender:)
method, add anelse-if
to your existing code to check for a different segue identifier,ShowPOIDetailSegue
- If that identifier is found, unwrap the selected row's index path from the tableview, and then grab the segue's destination view controller and cast it as an instance of
POIDetailViewController
(do these two steps together in a compoundif-let
) - If those unwraps are successful, set the detail view controller's
poi
property to the appropriatePOI
from the array you use in this class to track all POIs
At this point, the app should run and allow new POIs to be entered. They should appear in the main tableview and when tapped, the app should transition to a detail view to show the rest of the information about each POI.