Playing with iOS MapKit Part 4: Race Conditions, Other Bugs, Wrap-up

Playing With MapKit

Part 1 MapKit Tutorials 

Part 2 Reverse Geocoding and Custom Annotation Callouts

Part 3 Making it Pretty

Part 4 Race Conditions, Other Bugs, and Wrap-up

As the functionality and the look was coming into place, I took note of bugs that I saw.

The most insidious bugs are ones that don’t happen all the time or under conditions (ex. when internet is especially slow or the computer is especially fast). One example is the race condition.

What is a Race Condition?

A race condition is a situation when the sequence of asynchronous responses results in an undesired effect.

My Example

Very quickly after starting the app, I was tapping the current location dot and I was seeing “Current Location” in the bubble. It should have said the address that the address was closest to. If I waited a couple seconds to tap the current location, it would display the address as expected.

This led me to believe that I had a race condition.

Under normal conditions:

  1. The map updates the user location calling its delegate mapView:didUpdateUserLocation: which starts the reverseGeocoding call based on the user’s location.
  2. The reverseGeocoding response is received and the completion block sets the annotation’s title with the address of the user location.
  3. When the user location dot is tapped, it will display a custom bubble using the annotation’s title in the label.

Usually the internet is fast enough that the reverseGeocoding response returns before the user location dot is tapped.

The two things that are racing are

  1. the reverseGeocoding network call and
  2. the tap of the current location dot.

If 1 finished first, then the app would work as intended. If 2 finished first, the experience would be suboptimal.

Design Choice

One way to fix this is to update the label when the reverseGeocoding network call came back.

At the end of the completion block, I added a method call to updatePinCallout, which pretends that the user location dot was tapped again and reloads the address.

- (void)updatePinCallout
{    
  if (self.userLocationPin.selected) {
   [[NSOperationQueue mainQueue] addOperationWithBlock:^{
    [self.userLocationPin setSelected:YES animated:YES];
   }];
  }
}

Just remember to use the mainQueue to retap the dot or else the address won’t update on screen.

This change also fixed another bug that happened when the user location would jump when WIFI was enabled and the address label would not update to the new address.

Alternative Choice

Another thing that I found solved the problem pretty well was to zoom the map to the user location immediately, so that the animation didn’t even give a chance to tap the user location dot.

Other Bugs

Writing code for multiple scenarios unnecessarily

When I first implemented zooming to fit destinations, I only zoomed when the location was outside of the visible region. I realized that sometimes this would not be sufficient because sometimes the map would be zoomed way out, so I decided to account for that scenario too. I would zoom in if the destination was in the original visible area. This got complicated quickly.

Eventually, I realized that it was too much and just made it always zoom to the destination. The code went from 14 lines to 1.

Simpler is Better

Testing Days Later

I thought I was done with the project. Wrong. A few days later, I was trying out the app on the bus and came across two bugs.

  1. I was on a bus and the location was updating very quickly and constantly centering the map on the new location. The problem was that I wanted to look around the map and couldn’t do that without it changing while I was using it.
    • This is easily fixed by only zooming on the time the map loads.
  2. I was looking for a Pret A Manger. When I saw the results page, I found it utterly useless because all of them said the same thing and I couldn’t tell which location was where.
    • I think it would have been cool to add some directions as to how far each location was from my current location and in which direction or add the cross streets.

As the Pragmatic Programmer said:

“Test your software, or your users will.”

Where to next?

There’s certainly a lot of ways this can go. Add friends, add Facebook integration, add Yelp results, use Google Maps. That would be fun to do, but would lack direction.

For a product to be real, it must have a real use.

The way that this app fits into my life has something to do with lunch (ergo the name LunchTime). In an effort to build good habits, one of them is to walk 10K steps a day. As I’ve discovered, this means walking 1.3 hours a day. If I don’t plan to walk, I won’t get near 10K.

So over lunch, I like to walk 10 to 15 minutes away and back. I think it would be cool to draw a diamond around your current location to see how far you can walk in 5 and 15 minutes and show how far each location is.

Options abound. Looking forward to the next expedition.

It’s been fun working with MapKit. Time to play around with something else. Who knows? I might be looking at WatchKit, EventKit, or something else entirely.

Playing with iOS MapKit Part 3: Making it Pretty

Playing With MapKit

Part 1 MapKit Tutorials 

Part 2 Reverse Geocoding and Custom Annotation Callouts

Part 3 Making it Pretty

Part 4 Race Conditions, Other Bugs, and Wrap-up

After getting down the basic functionality, I wanted to polish up the app to give it a quality feel and to dig deeper into the nitty-gritty details of MapKit.

So I made a list of things that could be improved and proceeded to knock each of them out one by one.

To do list

*I had the most fun with this one.

  1. Remove the jumpy effect on loading
  2. Move bar buttons from toolbar to buttons on the map
  3. Make the callout for the first search result come up
  4. Make the zip code and city on the same line
  5. Make the map center and zoom when the current location is tapped
  6. After clicking the textbox, resign the first responder when the map is clicked
  7. Add Directions
  8. *Zoom to include the destination in the Routeviewcontroller
  9. Intelligently choose walking vs driving directions
  10. Make the starting region of the route, the same as that of the previous view

1. Remove the jumpy effect on loading

When the app loaded, the default map showed the United States and when the user location was updated, it would move center on the current location, leading to a jumpy effect (I didn’t know about setCenterCoordinate: animated: at the time). The jump came about a couple seconds after opening the app depending on the internet connection and lead to a laggy feeling.

Design Choice

Initially, I chose to not center the map on the current location because it was a quick fix. I let the user tap the current location to zoom in. I chose this because it was the easiest fix.

After some iterations, I decided it was better just to zoom in automatically.

Back to list

2. Move bar buttons from toolbar to buttons on the map

Many of the map apps that I’ve seen have floating buttons on the map instead of a toolbar. I planned to do this, but it didn’t seem worth the effort.

Design Choice

After looking at the default maps app and seeing that it used a toolbar too, I decided to save time and stick with the toolbar. I just separated the buttons to make it more symmetrical.

Back to list

3. Make the callout for the first search result come up

Before, I had the callout for the last search result come up. This lead to the map whipping to the last location when it was off the visible region.

Design Choice

Make the first search result come up.

I used enumerateObjectsUsingBlock to save the first item. In doing this, I found out that I needed to set my firstAnnotation object to __block, so that the change would be visible outside of the block. (More on StackOverflow.)

How do I select a MKPointAnnotation?

[self.mapView selectAnnotation:firstAnnotation 
animated:YES];

Back to list

4. Make the zip code and city on the same line

Custom Callout View

The view for the address callout was too small to show the whole line for city, state, and zip code.

Design Choice

The easiest way to fix this was to make the view wider and shorten the zip to five numbers.

Afterwards, I ran into problems with special places that had an extra line for the placename, so I had to add extra code to parse the formatted address lines in cases where there were two or three lines.

In the final version, the callout view is now a bit too big, so future work may be nice to set the size dynamically and even animated.

Back to list

5. Make the map center and zoom when the current location is tapped

Easy, call the zoomIn method that the zoom in button calls.

Back to list

6. After clicking the textbox, resign the first responder when the map is clicked

The touchesBegan: withEvent: method detects when I touch outside the textfield onto the map, so this was easy to fix.

- (void) touchesBegan:(NSSet *)touches withEvent:
(UIEvent *)event
{
    [self.searchText resignFirstResponder];
}

Back to list

7. Add Directions

With the route shown, it was natural to want to show the directions and the distances involved.

Design Choice

The easiest thing was to show the directions in a tableViewController and segue to it from a UIBarButton on the navigation bar of the directions page. This is pretty standard, so I just passed the instructions to a table view controller and displayed it in the cells.

The distances are currently in meters. That’s not very intuitive so it would be nice to have this in blocks.

Back to list

*8. Zoom to include the destination in the RouteViewController

The idea is that when I selected a venue which was outside the visible range, I wanted the map to zoom to fit the destination and my current location. While tedious, executing this was not hard when I saw down to work backwards from

[self.routeMap setRegion:self.adjustedRegion 
animated:YES];

How do I zoom in to fit two locations on a map?

Basically,

  • Get the coordinates for your location and the destination location.
  • Find the difference in latitude and longitude and scale this up by a multiplier. A multiplier of 1 will have both locations on the edges of the screen.
  • Make sure to get the absolute difference. Negative numbers are no good.
  • Make a MKCoordinateSpan with the ABSOLUTE differences in latitude and longitude.
  • Find the average latitude and longitude to get the center for the region.
  • Make the MKCoordinateRegion with the centerCoordinate and the span.
  • Find the adjustedRegion by calling regionThatFits on the region in the last step.
  • Set the MKMapView to that adjustedRegion.
- (void)resizeRegionWithDestination:(MKMapItem *)destination 
userLocation:(MKUserLocation *)userLocation
{
    NSLog(@"need to resize");
    CLLocationCoordinate2D destinationCoordinate = 
        destination.placemark.location.coordinate;
    CLLocationCoordinate2D userCoordinate = 
        userLocation.location.coordinate;
 
    double scaleFactor = 2;
    CLLocationDegrees latitudeDelta = 
        (userCoordinate.latitude - 
        destinationCoordinate.latitude)*scaleFactor;
    CLLocationDegrees longitudeDelta = 
        (userCoordinate.longitude - 
        destinationCoordinate.longitude) *scaleFactor;
 
    if (latitudeDelta < 0) {
        latitudeDelta = latitudeDelta * -1;
    }
    if (longitudeDelta < 0) {
        longitudeDelta = longitudeDelta * -1;
    }
 
    MKCoordinateSpan span = 
    MKCoordinateSpanMake(latitudeDelta, longitudeDelta);
    CLLocationDegrees averageLatitude = 
        (userCoordinate.latitude + 
        destinationCoordinate.latitude)/2;
    CLLocationDegrees averageLongitude = 
        (userCoordinate.longitude + 
        destinationCoordinate.longitude)/2;
    CLLocationCoordinate2D centerCoordinate = 
    CLLocationCoordinate2DMake(averageLatitude, 
        averageLongitude);

    MKCoordinateRegion region = 
    MKCoordinateRegionMake(centerCoordinate, span);

    self.adjustedRegion = [self.routeMap regionThatFits:region];
    [self.routeMap setRegion:self.adjustedRegion animated:YES];
}

The cool part about this code is that it doesn’t care if it’s zooming in or out. It just zooms perfectly to the right region. I had to play with the scalingFactor a couple times to get it to look right. 2 seems to work pretty well.

Back to list

9. Intelligently choose walking vs driving directions

To do this, I needed to get the estimated time for walking directions.

A note on directions. If the MKDirectionRequest has the transportationType set to walking and the destination is not walkable, then the service will return no results. That’s why the transportation type is defaulted to any.

MKDirectionsRequest *request = [[MKDirectionsRequest alloc] init];
 
request.source = [MKMapItem mapItemForCurrentLocation];
request.destination = self.destination;
request.requestsAlternateRoutes = NO;
request.transportType = MKDirectionsTransportTypeWalking;
 
MKDirections *estimatedTimeOfArrival = [[MKDirections alloc] initWithRequest:request];
 
[estimatedTimeOfArrival calculateETAWithCompletionHandler:^(MKETAResponse *response, NSError *error) {
    //do something with the response
}];

After I knew that there was no error, I would check to see if the response.expectedTravelTime was greater than 15 minutes (how much I’d be willing to walk). If it was, I would change the MKDirectionsRequest’s transportType to include driving and find the directions with the modified request.

With the asynchronous call within the completion block, this might be a good candidate for wrapping the asynchronous calls using promises.

Back to list

10. Make the starting region of the route, the same as that of the previous view

Pretty simple. Just pass the region from the first MKMapView to the search results view controller to the RouteViewController through the prepare for segues.

Back to list

At the end of this process, I had an app that I could actually show people and it feels really good.

Up next squashing bugs.

Playing with iOS MapKit Part 2: Reverse Geocoding and Custom Annotation Callouts

Playing With MapKit

Part 1 MapKit Tutorials 

Part 2 Reverse Geocoding and Custom Annotation Callouts

Part 3 Making it Pretty

Part 4 Race Conditions, Other Bugs, and Wrap-up

After following the tutorials in part 1, I wanted to keep exploring MapKit. As reverse geocoding was my next topic, I wanted to show the address of the current location in a callout (view that pops up above the pin).

To do this, I’ll need:

  1. A way to know when the current location was tapped
  2. A way to know the address of the current location
  3. A way to display the address in a callout

1. How do I know when the current location is tapped?

MKMapViewDelegate has a method called:

- (MKAnnotationView *) mapView:(MKMapView *)mapView 
viewForAnnotation:(id<MKAnnotation>)annotation

that is called when an annotation is tapped.

How do I tell that this annotation is my current location?

Notice that the annotation is any class that conforms to MKAnnotation.

Current location comes in a special class called MKUserLocation so you just need to test if the annotation is that class.

if ([annotation isKindOfClass:[MKUserLocation class]]
) {
...
}

Within this if statement, I need to turn the currentLocation into an address.

This MKUserLocation has a CLLocation property, a BOOL property for whether it’s updating, a CLHeading property, a title and a subtitle.

2. How do I find the address with coordinates? (Reverse Geocoding)

Apple provides a CLGeocoder class that has the method

- (void)reverseGeocodeLocation:(CLLocation *)location 
completionHandler:(CLGeocodeCompletionHandler)
completionHandler

All you need is the location which comes from MKUserLocation’s location property.

What does the completion handler return?

NSArray *placemarks, NSError *error

placemarks is an NSArray of CLPlacemarks. Each placemark has an addressDictionary. The key @”FormattedAddressLines” returns an array of formatted address lines.

Typically, there are three lines. One for address, another for city, state, and zip code, and one more for the country. In some situations, there are four lines where the first is the name of a venue.

3. How do I display the address?

One way is to set the callout for the annotation is to set the title of the annotation to the text you want in the callout. For example:

self.address = [NSString stringWithFormat:@" %@\n %@\n 
%@", street, cityState, country];
[(MKUserLocation *)annotation setTitle:self.address];

When I do this, the problem is that there is only one line and the rest of the address gets cut off.

Cut Off Callout

Adding line breaks to the title did not make it appear on additional lines, but only displayed the first line instead.

Callout title with line breaks

Messing with the left and right accessory buttons did not help either.

Callout with left and right accessory views colored red and blue
Callout with left and right accessory views colored red and blue

With no way to set more than two lines of text, I had to make a custom MKPinAnnotationView.

How do I make a custom annotation callout?

Since the callout is a property of the MKPinAnnotationView, I had to make a subclass of the MKPinAnnotationView and overwrite the setSelected: animated method.

- (void) setSelected:(BOOL)selected animated:(BOOL)animated
  1. Draw a label
  2. Set the text of the label with the annotation’s title
  3. Place a view as a subview of the MKPinAnnotationView subclass (which I called MultilineAnnotationView)
  4. Add the label as a subview of view.
setSelected
Why MKPinAnnotationView and not the default user location view?

The default user location view is a class that you cannot access or subclass.

Custom Callout View
The custom callout works! (but not perfectly)

Up next, making things look pretty.

Playing with iOS MapKit Part 1: MapKit Tutorials

Playing With MapKit

Part 1 MapKit Tutorials

Part 2 Reverse Geocoding and Custom Annotation Callouts

Part 3 Making it Pretty

Part 4 Race Conditions, Other Bugs, and Wrap-up

A main difference between a smartphone and any other phone is that smart phones can tell you where they are. What does location tell you? Location provides context about what you are doing, where you’re going, and by extension, who you are.

Apple makes it easy to show this information on a map with MapKit.

At the Flatiron School, I got a good foundation for learning frameworks, but hadn’t worked with MapKit yet. Since it felt core to many mobile apps, I decided to explore it.

Demo Video

Here is a demo of the finished app. All the code is on Github.

First Stop on the MapKit Train: Tutorials

Whenever I get into a new framework, I learn best by jumping right in and  doing it. Tutorials are a great way to get started. They help me focus by limiting scope and stay productive before my natural curiosity wants to go down some rabbit holes. I also don’t want to reinvent the wheel.

If I have seen further it is by standing on the shoulders of giants.

-Isaac Newton

Searching for iOS Mapkit tutorial, I find some by Ray Wenderlich, TechTopia, and AppCoda. All three have been really useful in the past. I went with the TechTopia one because it was written about iOS 7.

Tutorial 1: Make a MKMapView and Show the Current Location

Basically:

  • Add the MapKit framework
  • Make a MKMapView with Storyboards and import MKMapView
  • Assign the MKMapViewDelegate to the view controller
  • Set the MKMapView to show the current Location
  • *Not In Tutorial: Asking for Permission to Access User Location
  • *Set the location in Simulator
  • Zoom in on the MKMapView by changing the region
  • Change the MKMapView type
  • Update the MKMapView using the MKMapViewDelegate methods

*Most of this is already well explained in the tutorial. I want to point out two bumps on the road.

1. Simulator does not have a GPS, so you have to set the location by the menu bar: Debug -> Location -> Custom Location.

Google maps will give you latitude and longitude for any location if you click on the map. If it’s an icon, right click and click “What’s here?”.

Note: Sometimes the location doesn’t show up in the simulator the first time I run it. When I run it on another sized simulator, it works. Don’t know why this is.

2. More importantly, iOS 8 requires that you get permission to use the user location.

How to Get the Current Location Authorization Status

    CLAuthorizationStatus status = [CLLocationManager 
authorizationStatus];

CLAuthorizationStatus is an enum of

  • kCLAuthorizationStatusNotDetermined = 0
  • kCLAuthorizationStatusRestricted = 1
  • kCLAuthorizationStatusDenied = 2
  • kCLAuthorizationStatusAuthorized = 3 (Deprecated iOS 8)
  • kCLAuthorizationStatusAuthorizedAlways = kCLAuthorizationStatusAuthorized = 4
  • kCLAuthorizationStatusAuthorizedWhenInUse = 5

Statuses start out as kCLAuthorizationStatusNotDetermined

How to Ask the User for Location Authorization

If you want current location data only when the customer is using the app:

[self.locationManager requestWhenInUseAuthorization];

If you want current location data even when the customer is not using the app:

[self.locationManager requestAlwaysAuthorization];

Here I have my CLLocationManager as a property of the class. Change self.locationManager to the name of your locationManager.

How to Add Properties to your Info.plist

Even though you think you’ve requested authorization, you are likely still missing one more piece.

Properties List

In the Supporting Files Folder of your app directory, there is a Info.plist file.

It’s a properties list that your app uses through out the app.

You have to have a property in there for NSLocationWhenInUseUsageDescription (or NSLocationAlwaysUsageDescription depending on which permission your asking for), which tells the customer why you are asking for their location information.

Permission Popup

How to tell if you received location authorization

There is a delegate method for the location manager that tell you when the authorization status changes.

- (void)locationManager:(CLLocationManager *)manager 
didChangeAuthorizationStatus:(CLAuthorizationStatus)
status

The status here is the CLAuthorizationStatus.

Remember to set the locationManager’s delegate to the class that implements the delegate method. In this case, I’ve set the delegate to self inside my view controller.

self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;

Tutorial 2: Add Local Search with MKLocalSearchRequest and Display Results as MKPointAnnotation

Basically,

  • Add a textField so the user can input search terms
  • Add an IB action for the textFieldReturn to call the performSearch method
  • Add a performSearch method that sends a MKLocalSearchRequest and handles the MKLocalSearchResponse by parsing its array of MKMapItems into MKPointAnnotations

This was pretty straight forward. Apple makes the searches super easy by giving you completion handlers.

How to Perform a Local Search

You just need a MKLocalSearch object and a MKLocalSearchRequest object.

MKLocalSearch *search = [[MKLocalSearch alloc] 
initWithRequest:request];

and call

- (void)startWithCompletionHandler: 
(MKLocalSearchCompletionHandler)completionHandler

Tutorial 3: Find Directions with MKDirectionsRequest and Draw Them on the Map

Basically,

  • Add a ResultsTableViewController to show the names and phone numbers of the venues
  • Add a RouteViewController to show the route to the destination
  • Set up a MKDirectionsRequest with a source and destination in the RouteViewController
  • Make a MKDirections instance that calculates directions
  • Pass the MKDirectionsResponse to a showRoute method that adds an overlay of the polylines of the MKRoutes in the response to the map
  • Set up how the overlay will look

Notes

The tutorial sets up a custom UITableViewCell, but that’s not really necessary because you can set the title as the name and the subtitle to the phoneNumber.

Why am I in the middle of the ocean?

It’s important that you implement the MKMapView delegate method

- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:
(MKUserLocation *)userLocation

Otherwise, you’ll find yourself in the ocean next to West Africa a lot (that’s what happens when your coordinates are (0,0)).

How to Get Directions

Make an instance of MKDirections and call:

- (void)calculateDirectionsWithCompletionHandler:
(MKDirectionsHandler)completionHandler

Up next: Going beyond the tutorials

A Trip to the Met

Surrounded in a sea of options, I felt an urge to head to the Met.

Software development is art

On the way there, I tried to explain this urge. It became readily apparent as I walked through the halls of Egyptian wing that software development is as much an art as these. One can only hope to be in a museum some day. Though, any dreams that my software creations will outlast me may be overly optimistic.

Art requires repetition and experimentation

Looking at the Madame Cezanne exhibit, with it’s many renditions of the same lady, I am reminded that many versions were made before the final product was complete. This is an inherent part of the process of experimentation and exploration. Bad art has to be made before they can be judged bad and discarded to made room for good. This exhibit was only just a peek. Many shitty drafts were made that will never be on seen except by the artist.

Artists are judged on the height of their greatest accomplishment, not the first thing they make

Another thought that occurred to me was that people are judged on their greatest contributions or indiscretions. People only care at all about the early work when your best work has already been accepted as great. In the hindsight of a career, only highlights make it and most first moves are necessary to build the foundations of a great career. It’s really only by building a lot that one builds great things.

Let’s delay no further. Let’s get started.

Flatiron School Week 12 – iOS Full time Report

For notes on the first half of the program, check out the halftime report.

The End of the Beginning

These three months have been a tremendous experience. I recall other three-month periods where nearly nothing has changed. In stark contrast, I didn’t know anything about making apps three months ago and now I can make 80% of the good ones out there and I will soon be able to make the last 20%.

Amidst celebration, the feeling of the real world seeps in. The realities of finding a job are readily apparent. These three months have been a working vacation, a sabbatical, with no need to worry about worldly concern, just code. Yet, this search feels so much different from the post-college job hunt. That felt like gauntlet of hurdles, where the goal was to shape myself into the candidate that would be hired. This feels like a dating process. Maybe it’s always been that way, and I’ve only now grown mature enough to see it as such. I go into each interview, each conversation with as much thought about how much I like them as I do with how much they may like me.


Flatiron School Placements

This week, there’s been a lot of job advice, most of which I agree with wholeheartedly.

  • The placements team tell us how to prepare for the technical interview.
  • They tell us how to think about the long term (your career) not just your first job.
  • They tell us how to network.
  • They help us practice mock cultural and technical interviews.
  • They host talks to connect us with alumni and industry people.
  • They help us with our individual situations and questions.
  • All these things are meant to help us get a get a job.

Note: If you’re an international student, it may be hard to find a company to sponsor your work visa. 

Note 2: iOS developer make slightly more than Ruby on average.

I’m expecting the job finding process to go through a few iterations and take at least 2 months.

My advice: 1. Just like dating, you have to go out there, meet people and build relationships. 2. Keep coding to keep improving yourself. 3. Stop when you’ve found a place you’re excited to work for at least a year or two.


iOS Client Projects 

In interviews, people like to see that you’ve worked on projects before and especially if you’re worked with clients before.

One of the things that no one told me was that iOS students have client projects for the last four weeks. Ruby students work on their own projects.

I worked with a team for a client called HireCanvas, which makes the college campus recruiting process easier (how appropriate for my situation).  We helped them build out a iOS version of their web app.

Half of your time will be spend figuring out where to go

  • For the first eight weeks of labs, objectives and deadlines were established for us. Coding as a career gets real when I sit in front of a computer and spend half the time figuring what needs to be done when and what should be done next. Not having this structure makes me appreciate the time and thought put into designing a curriculum. On the project, we also have to make choices that will determine whether the project will be done in time. Do I use a cocoa pod or build my own?

Git only gets real in groups

Teamwork helps you figure out what makes good teammates

  • The other thing about working with people is that it helps you develop an intuition for who you would want to work with and who you wouldn’t. Sometimes people surprise you. You might think that an experienced programmer would be great to have on a team until you realize that commitment was a more important trait to look for.

Communication Communication Communication

  • As with any type of project, communication turned out to be key. When communication breaks down, people assume the worst and death spirals are started. Talking through it, you realize that the thing you were worried about was not that important to the other person.

A note on legal agreements

Read before you sign. Try to change what you don’t like.

Unlike software agreements, employment contract and non-disclosure agreements should be reason to pause. People will pressure you to sign, so you can get the job. They will tell you that it’s standard practice. That’s a whole lot of bs.

If they’re never going to use a part of the agreement, you shouldn’t have to agree to it.

Make sure you understand what you’re signing and if you don’t like it. Ask if you can change it. A lot of times it’s so boilerplate that the people you’re working with don’t even know what’s in it. If it can’t be changed, ask whether it’s worth taking on the work. I’d rather forgo a project than sign something I’ll regret later.

One thing the school could have done better was show us the legal agreements we would need to sign for the client projects and for attending the school before money and time was spent.


Overall Lessons

1. The number one goal for coming to Flatiron School is to learn how to be self-sufficient as a developer

Use the time to learn to fish and you will have skills for a lifetime. Use this time to try and fail, not produce a portfolio or kickstart your startup. The real world is not as forgiving.

2. Flatiron School brings together very nice, talented people. Build relationships with them.

For most of college, I didn’t appreciate the diversity of human talent and what I could learn from others. At Flatiron, the side projects I’ve seen really brings out people’s passions. I appreciate being around so many talented people (students especially).

3. Have enough living expenses for 6 months before you come to Flatiron

People who only had four months are now scrambling to find the first jobs they can. That’s an unenviable position to be in. Give yourself the time to think about what you want to do after Flatiron. You might be a different person by then.

4. Learning to code will make you feel more empowered than ever before

Not only can you make other people’s dreams come true, you can make your own reality.

Flatiron School Week 12 – Learn Swift or Objective-C?

I was asked whether a person with no iOS experience should learn Swift or Objective-C. After talking to a few people at the school, I’ve come to a simple conclusion.

Some Observations about Swift

In a couple days of playing with Swift, I’ve noticed that I could pick it up pretty easily. The frameworks are the same, but there’s some cool new syntax that will save a lot of typing (closures come to mind). I’ve also found that similar to learning Spanish and French at the same time, learning Swift will confuse your Objective-C syntax.

Learn Objective-C if you plan to be a professional iOS developer within the next year

For professional iOS developers, most companies are still in Objective-C and you will be expected to read and write it. Simple as that.

Learn Swift if you want to just work on your own side projects

Especially if you’re working on iOS development on the side, by the time you’re familiar enough with iOS frameworks, Swift will be more mature, more usable by then.

Flatiron School Presents – The Multipeer Connectivity Framework (Lattice)

Another Flatiron student and I were interested in the Multipeer Connectivity Framework in iOS, so we made a chat app called Lattice that uses multipeer in the event of a natural disaster as a demonstration of the technology.

I’m going to talk about how the basics of multipeer connectivity work.

The Multipeer Connectivity (MC) Framework

What does it do?

Multipeer allows devices to connect with others nearby without the internet.

How does it work?

Multipeer Connectivity is an implementation of mesh networking, creating a local network between devices within Wifi or Bluetooth range. Not only are new devices connected with devices within range but also with all devices that those devices are connected to, even if the destination device is not within range of the sender.

That’s the real power of mesh networks. If permitted, devices can send messages relayed through other devices.

How might this be useful?

  1. Mesh networks allow communication when internet infrastructure is damaged (such as natural disasters).
  2. Mesh networks allow communication when internet access is restricted by governments, seen in the protests of Hong Kong.
  3. Mesh networks allow communication in internet-less situation (camping trips, road trips, subway commutes, and foreign vacations).

Lattice – Demo Project

Before we dive into the nitty gritty, I’ve placed Lattice on Github, so you can see exactly how the snippets below are used.


Setting up the MCManager

We have a MCManager class, similar to an API manager or data store for Core Data. Four properties need to be set up.

MCPeerID

_peerID = [[MCPeerID alloc] initWithDisplayName:displayName];

This is the name of your device.

MCSession

_session = [[MCSession alloc] initWithPeer:self.peerID securityIdentity:nil encryptionPreference:MCEncryptionNone];
_session.delegate = self;

This is the session that your device will start. Think of a session like a chatroom.

MCNearbyServiceAdvertiser

_advertiser = [[MCNearbyServiceAdvertiser alloc] initWithPeer:self.peerID discoveryInfo:elements serviceType:LatticeServiceType];
self.advertiser.delegate = self;
[self.advertiser startAdvertisingPeer];

This adverser tells nearby browsers that it is looking to connect with a particular serviceType. DiscoveryInfo is a dictionary that the browser will receive when it finds this advertiser.

MCNearbyServiceBrowser

_browser = [[MCNearbyServiceBrowser alloc] initWithPeer:self.peerID serviceType:LatticeServiceType];
self.browser.delegate = self;
[self.browser startBrowsingForPeers];

This browser looks for advertisers of a particular service type to connect to.


Connecting to Other Devices

Lattice, the demo app, will have an advertiser and browser running at the same time on each device.

Browser Finds Peer, Invites Peer

- (void)browser:(MCNearbyServiceBrowser *)browser foundPeer:(MCPeerID *)peerID withDiscoveryInfo:(NSDictionary *)info
{
   [self.browser invitePeer:peerID toSession:self.session withContext:nil timeout:10]
}

When a browser finds an advertiser, it can parse the discoveryInfo that the advertiser set when it was created. In this case, we want the devices to connect automatically, so the browser sends an invitation to connect to the browser’s session.

Advertiser Accepts Invitation

- (void)advertiser:(MCNearbyServiceAdvertiser *)advertiser didReceiveInvitationFromPeer:(MCPeerID *)peerID withContext:(NSData *)context invitationHandler:(void (^)(BOOL, MCSession *))invitationHandler
{ 
    invitationHandler(YES, self.session); 
}

Since we want the advertiser to connect automatically, the advertiser will reply YES to the invitation.

Session Confirms Connection

- (void)session:(MCSession *)session peer:(MCPeerID *)peerID didChangeState:(MCSessionState)state

We can indeed confirm that the two devices are connected with this delegate method from the session. The session will tells us that the peer is now in the connected state.


Sending and Receiving Messages

Sending From the View Controller

[self.multipeerManager.session sendData:messageData toPeers:self.multipeerManager.session.connectedPeers withMode:MCSessionSendDataUnreliable error:&error];

Messages are sent from the session to the peers in the session.

Receiving In the MCManager

- (void)session:(MCSession *)session didReceiveData:(NSData *)data fromPeer:(MCPeerID *)peerID
{
    //Kicks off a notification to the View Controller 
}

Messages are received by the session on the other devices. In Lattice, we triggered a notification with each message received.

Catching the Notification In the View Controller

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(peerDidReceiveDataWithNotification:) name:@"MCDidReceiveDataNotification" object:nil];
- (void)peerDidReceiveDataWithNotification:(NSNotification *)notification
{
    NSData *messageData = notification.userInfo[@"data"];
    NSArray *messages = [NSKeyedUnarchiver unarchiveObjectWithData:messageData];
    [self.demoData.messages addObject:messages[0]];
}

The notification was handled by the view controller to display the new message.


Limitations

iOS only

Multipeer Connectivity is a iOS framework.

Range can be limited on Bluetooth

We found it to be about 60 – 100 feet.

Downloading the app requires the internet?!

There should be a way for the app to spread virally with no internet.

Limited usefulness in zombie apocalypse

This would be great for finding survivors nearby without having to go room by room through scary dark buildings. During night when the zombies are outside, the bluetooth signal may not be long enough to communicate between buildings.


Special Thanks

Peter Fennema for showing how to connect via multipeer automatically

Jesse Squires for the messaging user interface: JSQMessagesViewController

Flatiron School Week 11 – Week in Review

Week 3 of Client Project

One of our teammates have been dealing with an emergency for most of the last two weeks, so we’re down to three people.

The Science Fair is Wednesday and we want to have something to showable, so we scoped down our project to just what needed to be shown.

From Monday to Tuesday, our team and our app really came together. We are in the performing stage of the team “form, storm, norm, perform” process. I’m glad that my investment of time paid off. Everyone pulled their own weight.

I’m really impressed why what we were able to do in 2 weeks. People were really impressed at the Science Fair.

I’ve been so focused that I haven’t really been paying attention to how the other client projects were going. It looks like they had bigger clients and bigger expectations. That’s the benefit of having a younger client.

We ended the week with a huge celebration over at Sammy’s. So much fun.

Flatiron School Week 10 – Week In Review

Week 2 of Client Projects

Notes to Self

This week felt like I was reliving my first year out of college when I was working as a paralegal/project manager in a client facing team. That year, I learned more about communication and relationship building than anything else, themes that came up this week.

  • Giving feedback is one of the most difficult conversations between people. Admitting that you’re wrong is another. All difficult conversations are best done promptly.
  • On a small team, having a team member that isn’t able to contribute at the same level is a productivity killer because it means that productive people need to stop and invest in that team member. (Sam Altman has more on this topic)
  • Communication is key. When communication breaks down, trust erodes and people assume the worst.
  • As much as possible, it’s good to talk directly with the people involved. You build trust this way.
  • Don’t hesitate to pick up the phone.
  • Teams should have a single point of contact when working with clients to provide updates.