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
UIPickerViewand aUIButtonon the view. - Wire up an outlet for the
UIPickerViewin theSearchViewController.swiftfile. - Set the delegate and datasource properties of the
UIPickerView. - Implement the required datasource methods. This
UIPickerViewshould 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
UIPickerViewrow. - Wire up an action for the
UIButtonon 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.swiftclass file and define a newRepresentativeclass. - 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
Representativemodel 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
NetworkControllershould 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
NSURLendpoint. - Write a function that will take an
NSURLand 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 theNSDatafrom the network call as it's parameter. If it is unsuccessful, the completion closure should still be called, butnilshould 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
RepresentativeControllershould have a method on it that allows the developer to pass in the search parameter and, through a completion closure, provide a an array ofRepresentativeobjects.- 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 wecatchan exeception, call the completion closure with an empty array as the[Representative]parameter. If the NSData can be serialized, create aRepresentativeobjects 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 theUITableViewControllerscene 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 yourRepresentativeControllerto 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 theUITableViewControllerscene toResultsDetailTableViewController. - Add a show segue from the prototype cell on
ResultsTableViewControllerto theRepresentativeDetailTableViewControllerscene. 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
textLabellarge font and set the minimum font size (in case a representative has a long name). Set thedetailTextLabelto 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. ThetextLabelwill be smaller than thedetailTextLabel. Make changes to the cell to reflect this. Give this cell an identifier.
- Implement the required
UITableViewDataSourcemethods. - 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 toswitchon theindexPath.rowand dequeue the cell with the identifier we want at that row and set the data to the correctRepresentativeproperty. - 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.