If you build it, they will find zip codes

July 29, 2014

ZipGet's main screen

I’ve written an app in Swift. Put simply, the app helps you find zip codes. Enter a city or landmark, pan and zoom your way across the globe, or center on your current location to see a zip code. If a friend has ever given you his credit card to use at a gas station, you’re curious what zip codes are near your house, or you’re trying to mail a birthday card to your friend in Boston, ZipGet(working title) can help you out. The interface is essentially just a map decorated with a big label for the postal code and some buttons. I’d been kicking around this idea for years, and the confluence of Apple’s releasing Swift and my working for an awesome company means I got the chance to write it as my job. I have worked in Objective-C on a few occasions, but I am no expert. Syntactically, switching to Swift from JavaScript, or likely anyother languages with curly braces, was painless. The real difficulties arose when I began adding Cocoa libraries to my project.

Adopting Protocols

While Apple’s user-facing products tend toward simplicity and intuitiveness, their development kits do not. The first major issues I encountered writing the app concerned adopting the MKMapViewDelegate protocol for my view controller. This signature can be found in the documentation for that protocol:

@optional func mapView(_mapView: MKMapView!, regionDidChangeAnimated animated: Bool)

Interestingly, the signature differs from what you actually write in your delegate definition:

func mapView(mapView: MKMapView!, regionDidChangeAnimated animated: Bool)

What happens when one incorrectly implements an optional delegate function is, perhaps not surprisingly, nothing. Debugging does not reach breakpoints, log messages are not output—it’s a dark, confusing time. I eventually figured out my mistake. It’s not obvious that the underscore in the documentation version of the signature is not necessary in the implementation version. What helped me determine that I had implemented the function correctly was the Quick Help pane in Xcode. When your cursor sits in a function’s name, the Quick Help pane should populate with relevant information from the documentation.

How, well, helpful.]
The Quick Help pane confirms that I have conformed to the MKMapViewDelegate protocol.

Dealing with JSON

After I got the map and view controller correctly hooked up, things progressed smoothly until I began parsing the JSON returned by the GeoNames service. The app uses a third-party library called AFNetworking to send its requests, an instance of the AFHTTPRequestOperationManager class in particular. I use the class’s GET method and supply a couple of closures to handle success and failure. Since AFNetworking is an Objective-C library being bridged to Swift, the success closure unfortunately maps the response object from id to AnyObject.AnyObject is a construct in Swift that offers no type information, so pulling the JSON response apart into the bits I am interested in requires extensive use of type casting. The result is less than elegant.

let json = response as [String:AnyObject]let postalCodes: AnyObject? = json["postalCodes"]let postalCodesArr = postalCodes as [[String:AnyObject]]if !postalCodesArr.isEmpty {    let first = postalCodesArr[0]    if let postalCode: AnyObject = first["postalCode"] {        onSuccess(postalCode as String) return    }}

The Objective-C code to accomplish the same thing is almost identical, and even a little shorter.

NSDictionary *responseDict = responseObject;NSArray *postalCodes = [responseDict valueForKey:@"postalCodes"];NSDictionary *first = [postalCodes firstObject];if (first) {     NSString *postalCode = [first valueForKey:@"postalCode"];     NSLog(@"%@", postalCode);     return; }

It’s disappointing that Swift offers no real improvements here. Hopefully, there will updates to existing libraries, or entirely new libraries, that will take advantage of Swift’s modernity. As I mentioned in my last post, David Owens has already devised an expressive library for modeling JSON in Swift. Unfortunately, I was unable to simply cast the response variable to his JSON class as I had hoped.

Code Organization

When writing JavaScript, I have a nasty habit of curating poorly organized clumps of related functions and calling them prototypes. Unfortunately, I think Swift is perfectly suited to let me continue doing so. Having said that, Swift also provides at least one construct that some people have already championing as a best practice: using extensions to implement protocols and to modularize code. I set aside an extension for each of the protocols my view controller subscribes to, and I think it does help improve navigation. It’s at least better than not using extensions. Check out ViewController.swift to see what I am talking about.

On a related note, I used CocoaPods for the first time in the course of creating this app. It’s a dependency manager, much like Bundler for Ruby applications. I didn’t actually do anything related to Swift with CocoaPods, aside from provide Objective-C libraries to use via a bridging header. It is a very simple tool to use. Like Bundler, CocoaPods asks for a file(a Podfile) defining what libraries and what versions of those libraries to include. I plan to continue using this solution whenever possible to manage projects I may undertake in the future. Its contribution to the organization of the project consists of maintaining dependencies in a secondary project and requiring the use of an Xcode workspace, which isn’t any trouble considering Xcode’s “Welcome to Xcode” window and its list of recent items.

All in all, Swift lent itself to my finally realizing an app idea of my very own from start to finished enough. Sure, I could add a bunch of features and polish, but what I’ve built is a viable App Store listing, in my humble opinion. If you would like to explore the source code on your own, it’s here!