Overview: An Application Definition Statement is a one or two line statement answering these two questions: What's the app do? and Who is it for?
Here's ours: RIT Maps is a mapping application that displays RIT buildings and relevant locations to prospective students and their parents.
Requirements and Grade Rubric
(85%) The following is the minimum capability that is required of the App:
- Master/Detail template (5%):
- Make the app Universal, but you are only required to build the iPad version.
- Make sure the Edit and + buttons from the template are gone, and that the titles of the View Controllers are "Places" and "RIT Map"
- The Master view controller is a table view, the Detail view controller will display a
MKMapView
.
- Data (5%):
- The app will load the JSON data file of buildings and convert it to an array of
NSDictionary
instances. - The
NSDictionary
instance data will be stored in a model class namedRITBuilding
- The app will load the JSON data file of buildings and convert it to an array of
- The
RITBuilding
class (10%):- The
RITBuilding
class designated initializer will be:- (id)initWithDictionary:(NSDictionary*)dictionary
Model
classes should validate their data. Some of the buildings returned from the web service are lackinghistory
andfull-description
keys. If any of the NSString values come back from the JSON dictionary asnil
, initialize them to a default value. See Hints below for an example.- The
RITBuilding
class will conform to theMKAnnotation
protocol - Because the buildings will never move, initialize the values of
coordinate, title, and subtitle
in the designated initializer - will have the following properties:
- The
@property (nonatomic, copy) NSString *name; @property (nonatomic, copy) NSString *mdo_id; @property (nonatomic, copy) NSString *bDescription; @property (nonatomic) float latitude; @property (nonatomic) float longitude; @property (nonatomic, copy) NSString *polygon_id; @property (nonatomic) NSMutableArray *path; @property (nonatomic, copy) NSString *image; @property (nonatomic, copy) NSString *abbreviation; @property (nonatomic, copy) NSString *history; @property (nonatomic, copy) NSString *fulldescription;
- The table view (15%):
- will display all 75
RITBuilding
instances and display both a title and a subtitle. - The names of the buildings will appear alphabetically.
- When a table row is tapped, the map will zoom in on and select that annotation on the map.
- will display all 75
- MapView (50%):
- There will be an annotation for every
RITBuilding
(5%) - The map will display correctly when the device is rotated. (3%)
- The users current position will be displayed on the map. (2%)
- There will be a
UISegmentedControl
in the navigation bar than controls what type of map will be displayed. The default mapType will be hybrid. (5%) - When the app starts up, the George Eastman Building will be selected at the center of the map, and the map will be at an appropriate zoom level. You'll have to search the array for the right
RITBuilding
instance. (5%) - A selected annotation will display both a title and a subtitle and a callout button. (5%)
- Tapping a annotation callout will reveal the
fulldescription
information for that building instance. This information will appear in aUIPopoverController
. See this Stack overflow post for ideas how to accomplish this. Also check out thisUIPopoverController
tutorial (25%)
- There will be an annotation for every
Ideas for enhancements (Up to 25%)
- Draw a polygon overlay around the currently selected building. Use the
path
property ofRITBuilding
. Be sure to do this using the iOS 7 classes ofMKPolygon
andMKOverlayRenderer
- Draw overlays or colored annotations (a different color from buildings) at points of interest like parking lots, food locations, coffee shops, or bathrooms. To do this you'll need to hit up the RIT MIS for more data - see the sample links on the course outline page. These new locations could be in their own sections in the tableView, or filtered via a
UISegmentedControl
- Make the app Universal. It will have a Master-Detail style on the iPad, and a Navigation or Tab Bar style on the iPhone.
- Have the map start in a 3D state - see docs below. Note: changing the
MKMapCamera
of the map only works on aMKMapTypeStandard
map. - Give the table a search bar: see http://www.raywenderlich.com/16873/how-to-add-search-into-a-table-view for ideas how to get this done. Make aure that tapping a building in the filtered search field zooms in on and selects the correct building. Note: there is a change you need to make to get this to work with iOS 7.
changing this line:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];
to this:UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"Cell"];
should fix the issue. MKLocalSearch
- see video and docs below- Watch (or read the PDF) the Whats New in Map Kit presentation from 2013 WWDC for ideas - it's here
- Browse the Location and Maps Programming Guide for ideas.
- ???
Deductions
- (-20%) The project won't compile. (Be sure that your resources have been imported and are in your project directory!)
- (-20%) The completed project is not installed on your iOS device.
- (-??%) Egregious violations of MVC or Coding Standards
Coding Standards
- MVC!
- Separation of Concern - You should have multiple Objective-C classes, with each class having well-defined functionality accessed through a public interface.
- D.R.Y. - Don't Repeat Yourself. Repeated blocks of nearly identical code should be factored out and placed in a separate method.
- No "magic numbers" (unnamed numerical constants) - declare C style constants or enums or
#define
s instead. - Objective-C code conventions: public properties and methods declared in .h file, private ivars declared in .m and begin with an underscore, class names are capitalized, method names are in lower case.
- Well commented code. Each and every method you wrote gets a comment indicating what it does.
- There should be no compile time or run time errors.
Hints
- This Tutorial covers the following:
- Adding a MapView to your project
- Switching the map type with
UISegmentedControl
- Adding an image overlay to the map
- Annotations
- Adding lines, polygons, and circles to the map.
- To get the user location to display on the map, head over to Storyboard, select the map and look for the applicable checkbox under the attributes inspector.
- To get the map to appear correctly when the device is rotated, head over to Storyboard, select the map and the choose Editor > Resolve Auto Layout Issues ... > Reset to Suggested Constraints. 90% of the time this fixes auto-layout issues.
- The path parsing code looks like this (make this a private helper method in
RITBuilding
):
- (NSMutableArray *)parsePath:(NSString *)path{ NSMutableArray *array = [NSMutableArray array]; NSArray *points = [path componentsSeparatedByString:@"|"]; for (NSString *p in points) { NSArray *values = [p componentsSeparatedByString:@","]; float latitude = [values[0] floatValue]; float longitude = [values[1] floatValue]; CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(latitude,longitude); [array addObject: [NSValue valueWithMKCoordinate: coordinate]]; } return array; }
- If you want to sort an array of custom objects there are several ways to do it. See this Stack overflow post for some ideas. Here is some code that will sort a mutable array:
// sort mutable array alphabetically NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"lastname" ascending:YES]; NSArray *sortDescriptors = @[sortDescriptor]; [myMutablePeopleArray sortUsingDescriptors:sortDescriptors];
- If you want to find an object (or objects) in an array that has a property of a certain value, use
NSPredicate
:
// a predicate is a statement or assertion // in this case, that the abbreviation property is equal to @"GOL" NSPredicate *predicate = [NSPredicate predicateWithFormat:@"abbreviation == %@", @"GOL"]; NSArray *filteredArray = [self.buildings filteredArrayUsingPredicate:predicate]; id match = [filteredArray objectAtIndex:0];
- Model classes should validate their data. If any of the
NSString
values come back from the JSON dictionary asnil
, initialize them to a default value. Here's an example:
if(d[@"name"] == nil){ self.name = @"No name found"; } else { self.name = d[@"name"]; } // or as a one-liner using the ternary operator self.name = d[@"name"] ? d[@"name"] : @"No name found";
- If you would like to display an image along with the
fulldescription
in the "Building Detail" popover, the best solution is a create aUIWebView
to fill the entirety of the view controller. To initialize that web view with the right HTML, you probably want to create a template file, load it, and then plug in the correct values for the current building. See my Stack Overflow post for hints on how to load and initialize the template.
- If you want to create an overlay on the map, you'll have to translate the
NSMutableArray
of points (RITBuilding.path
into an old-fashioned C array ofCLLocationCoordinate2D[]
points. This is because theMKPolygon
initilaizer is one of the few places that iOS wants a C-array rather than anNSArray
. There's no built-in method to do this, so here's the code:
// get our NSArray NSArray *array = [building path]; // initialize a C-array of points CLLocationCoordinate2D points[array.count]; // loop through the C-array and initialize it for (int i=0; i<array.count; i++){ points[i] = [(NSValue*)array[i] MKCoordinateValue]; }
- Finally, if you are working on some of the optional features you may run into a situation where you want to pass data between view controllers. Passing from the "parent VC" to a "child VC" is easy - just create a property in the child.
But passing from the "child VC" back to the "parent VC" is trickier - see this post for an example of how to do this by writing a delegate: http://stackoverflow.com/questions/5210535/passing-data-between-view-controllers.
You could also use notifications, or the
self.presentingViewController
property and a block (look over the Blackjack-5 "About Window" ICE).
Screen Shots
Submission
- ZIP up and post to dropbox before due date. This is worth 15% of final grade.
- Install this on your iOS device and bring it to class.
- Document that you met the requirements, and be specific about any enhancements and extra credit you did. Paste this into the comments field of the dropbox.
- Max grade is 110%
App Feature Brainstorming (not part of the requirements above)
Let's come up with some app features in class that will meet out application definition statement. A good app can be though of as a "Focused solution to a well-defined problem", but here, let's come up with every feature we can that might help our target audience.