Students will build an app to get the representives (law makers) in a user-requested state to practice asyncronous network requests, working with JSON data, closures, and intermediate table views.
Students who complete this project independently are able to:
- use NSURLSession to make aysncronous network calls
- parse JSON data and generate model object from the data
- use closures to execute code when an asyncronous task is complete
- build custom table views
Set up a scene to allow the user to selected a state and then tap a button that will perform a network call with the requested state, when the network call is complete, segue to the next view controller (RepresentativeTableViewController, discussed below).
- Place a
UIPickerView
and aUIButton
on the view. - Wire up an outlet for the
UIPickerView
in theSearchViewController.swift
file. - Set the delegate and datasource properties of the
UIPickerView
. - Implement the required datasource methods. This
UIPickerView
should display all the states. For your convenience, an array of all the state abbreviation is included. - Implement the delegate method that will allow you to set the titles of each
UIPickerView
row. - Wire up an action for the
UIButton
on the control event touch up inside.
Create a Representative
model class that will hold the information of a representative to display to the user.
- Create a
Representative.swift
class file and define a newRepresentative
class. - Go to a sample endpoint of the Who is my Representative API and see what JSON (information) you will get back.
- Using this information, add properties on
Representative
.name: String?
party: String?
state: String?
district: String?
phone: String?
office: String?
link: String?
- Create an init method with a parameter of a dictionary. This is the method you will call and pass your json dictionary to initialize your
Representative
model objects. Remember to use a sample endpoint to inspect the JSON you will get back and the keys you will use to get each piece of data.
Create a NetworkController
class. This will have methods to build the different URLs you might want and it should have a method to return NSData from a URL.
- The
NetworkController
should have some static constant that represents yourbaseURL
. - Write a function that will take in a search term (the solution code uses a state abbreviation) and return an
NSURL
endpoint. - Write a function that will take an
NSURL
and a completion closure (dataAtURL:completion:
). The parameter of the completion closure should be of typeNSData?
and the closure should returnVoid
. This method will make the network call and if successful will call the completion closure with theNSData
from the network call as it's parameter. If it is unsuccessful, the completion closure should still be called, butnil
should be the parameter. - At this point you should be testing your network controller method
dataAtURL:completion:
to see if you are getting data returned.
As of iOS 9, Apple is boosting security and trying to require developers to use https. For this API, you must have a paid API account to use https. For the sake of this app and learning, we will turn off this security feature. The error message should describe the issue about App Transport Security blocking a cleartext HTTP. A workaround to Apple's requirements is to add a key-value pair to your Info.plist. This key-value pair should be: App Transport Security Settings : [Allow Arbitrary Loads : YES].
Create a RepresentativeController
class. This will have methods that are called by the view controller to get [Representatives]
through completion closures.
- The
RepresentativeController
should have a method on it that allows the developer to pass in the search parameter and, through a completion closure, provide a an array ofRepresentative
objects.- This method should use the NetworkController to get the NSURL.
- This method should call the NetworkController's dataAtURL method to get the NSData at the URL created in the previous bullet point.
- In the closure of the dataAtURL check to make sure you actually get NSData back, not a nil value. If nil, call this methods completion with an empty array as the value for the
[Representative]
parameter, else continue. try
(<- *Hint, Hint) to serialize the NSData to JSON objects. If wecatch
an exeception, call the completion closure with an empty array as the[Representative]
parameter. If the NSData can be serialized, create aRepresentative
objects and call the completion closure with the populated array.
Implement the SearchViewController
class. Implement the IBAction of the button to perform the search, once the search is complete, perform the segue to the ResultsTableViewController
- Add an additional scene to the Storyboard. Use a
UITableViewController
. Create a class fileResultsTableViewController.swift
. Set the class of theUITableViewController
scene toResultsTableViewController
. - Add a show segue from the
SearchViewController
(not from theUIButton
) to theResultsTableViewController
. Give the segue an identifier. - In the
ResultsTableViewController
, add a property of type[Representative]
. - In the
SearchViewController
, add a property of type[Representative]
. - In the IBAction of the
SearchViewController
'sUIButton
, use yourRepresentativeController
to perform the search based on theUIPickerView
's selected state. Once the search is complete, set theSearchViewController
's[Representative]
property to the results you recieve in the closure. Call theperformSegueWithIdentifier:sender:
method. - Implement the
prepareForSegue:sender:
method. Check to make sure the identifer is the correct one, get thedestinationViewController
, set it's[Representative]
property to results you recieved from the search.
Add a prototype cell to the ResultsTableViewController
. Add a detail view with a representatives details that will show when the user taps a representative from the ResultsTableViewController
. Use custom table view cells to display the representatives details.
- Add a prototype cell to the
ResultsTableViewController
'sUITableView
. Give it an identifier. - Add an additional scene to the Storyboard. Use a
UITableViewController
. Create a class fileRepresentativeDetailTableViewController.swift
. Set the class of theUITableViewController
scene toResultsDetailTableViewController
. - Add a show segue from the prototype cell on
ResultsTableViewController
to theRepresentativeDetailTableViewController
scene. Give the segue an identifier. - Add two prototype cells, both of style subtitle. On one cell, we will display the representative's name, state, district, and state image. Make the
textLabel
large font and set the minimum font size (in case a representative has a long name). Set thedetailTextLabel
to a smaller font than thetextLabel
. Give this cell an identifier. One the second cell, we will display the representative's details (phone, office, website, party) with a header label describing the information in that cell. ThetextLabel
will be smaller than thedetailTextLabel
. Make changes to the cell to reflect this. Give this cell an identifier.
- Implement the required
UITableViewDataSource
methods. - Add a property of type Representative to the
RepresentativeDetailTableViewController
. - In the
prepareForSegue:sender:
method, check if the segue's identifer match the one set in Storyboard, get the destination view controller, and set the Representative property on theRepresentativeDetailTableViewController
.
Implement the required UITableViewDataSource
methods. In the tableView:cellForRowAtIndexPath:
method, switch
on the indexPath.row
to make sure you dequeue and return the right cell based on the row.
- Implement
tableView:numberOfRowsInSection:
method. Since we know exactly how many cells we want to display and it doesn't change, hard code the number of rows. - Implement
tableView:cellForRowAtIndexPath:
method. Since we need to customize each cell will data pulled from different properties, we are going toswitch
on theindexPath.row
and dequeue the cell with the identifier we want at that row and set the data to the correctRepresentative
property. - Also when the view appears, set the title of the view controller to the representative's name.
- Notice how after tapping the search button, the app hangs and doesn't do anything while the network call is being performed. Give visual feedback to the user that the search is being conducted.
- Implement another way for users to find their Congressman/Congresswoman.
- If no Represenatives were "found", notify the user that a search failed.
- Make the phone, office, and website labels links that would call, open a map view, and open a web view.
Please refer to CONTRIBUTING.md.
© DevMountain LLC, 2015. Unauthorized use and/or duplication of this material without express and written permission from DevMountain, LLC is strictly prohibited. Excerpts and links may be used, provided that full and clear credit is given to DevMountain with appropriate and specific direction to the original content.