Universal App Template Rewrite

Almost 3 Years Ago

Just when I thought I had a somewhat decent grasp on developing and deploying iOS apps Apple came out with the iPad and threw a whole new element in the mix when it comes to developing.

It was almost three years ago that I published the first blog about my Universal App Template. I was inspired by, at the time, a little tutorial by a guy you might have heard of…Ray Wenderlich). His tutorial really helped me with a project I was working on and get through stumbling blocks. I wanted to provide a set of examples that any iOS developer could refer to that was straightforward and get up and running with creating a universal app in as short of time as possible.

Over the following months I added additional features such as iAd support, tabbar controller and iAd with tabbar support. Since then it is still the most visited article and starred/forked repo that I have.

Bueller, Bueller…

Over the years that followed I got busy and wasn’t able to keep up with the iOS updates, new features requested or bugs. The project was quickly becoming outdated.

I’m happy to say that I’ve carved out sometime to update this project. The plan is to start with the master branch, which is the most basic example, and update it from the ground up. I’ll then move on to the “feature” branches. I’m dropping support for iOS 3.2, 4.x and 5.x. Due to the fact that the iOS upgrades happen so rapidly, thanks to OTA, and iOS 7 is being released in less than a month, this is the perfect time to hit the reset button. The project, as well as, feature branches, will support ARC. I’ve also spent some time cleaning up the code base and removed a lot of duplicated code.

If you still need access to the “old version” I’ve tagged it.

No developer is perfect and I’m sure there are tons of things to improve so please drop me a line or file a bug and I’ll fix it ASAP.

Taming Core Location

In today’s mobile development environment using the device’s GPS in some shape, form or fashion is a given. Apple provides a great toolset for developers to access and utilize this functionality, but this is often done carelessly. I am not talking about privacy concerns or the misuse of the data, but many developers, myself included early on, had a poor code design implementation. The characteristics of such are usually:

  • CoreLocation implementation that was always tied directly to a particular UIViewController
  • Set the accuracy to kCLLocationAccuracyBest
  • Set filtering to kCLDistanceFilterNone.
  • Requests way to many location updates

Let’s examine each reason why these are not the best practice

Tight Coupling is Wrong

This is a more of a development practice that developers should always attempt to achieve in their code. There are always examples and uses cases as to why you would have to break this paradigm, but is still goal none the less. What we generally see, and most tutorials on the topic do this, is that the UIViewController sublcass will conform to the CLLocationManagerDelegate protocol, setup the manager and properties and listen for callbacks. I guess that is OK if you have only one use case and user interaction that requires CoreLocation, but in most cases you need to access CoreLocation more than once, thus you have to duplicate the same code. The “C” in MVC has now broken it’s intended contract and you have tightly coupled code.

Less Accuracy is More

This lesson is pretty simple. The more accurate the location you request, the longer it takes to get and the more battery power is drained. The faster the battery is drained the faster the iOS user gets pissed. The simplest example is a weather application. There is NO need to request such a detailed location. By setting your accuracy to kCLLocationAccuracyThreeKilometers you save yourself, and most importantly the user, time and end up with same information. Weather is usually shown based on a region area. i.e. zip code or city.

“For example, setting the desired accuracy for location events to one kilometer gives the location manager the flexibility to turn off GPS hardware and rely solely on the WiFi or cell radios. Turning off GPS hardware can lead to significant power savings.” – CoreLocationManager Reference

Filters are For Your Protection

Unless you are creating a turn-by-turn navigation app set a filter. Getting a location updates every half step or every second doesn’t add any value to the task of the application, but does have the same downsides as mentioned above. Poor battery life and horrible user experience.

You Don’t Need Updates Every Two Feet

This error is really an error in judgement. Apple provides developers with the fine grained control via distanceFilter and desiredAccuracy, but should be used sparingly and with apps that require multiple checks throughout the app session for location updates.

This service is most appropriate for applications that need more fine-grained control over the delivery of location events. Specifically, it takes into account the values in the desiredAccuracy and distanceFilter property to determine when to deliver new events. The precision of the standard location services are needed by navigation applications or any application where high-precision location data or a regular stream of updates is required. However, these services typically require the location-tracking hardware to be enabled for longer periods of time, which can result in higher power usage.

For apps that don’t require a constant stream of updates it is best to use start/stopMonitoringSignificantLocationChanges.

This method is more appropriate for the majority of applications that just need an initial user location fix and need updates only when the user moves a significant distance. This interface delivers new events only when it detects changes to the device’s associated cell towers, resulting in less frequent updates and significantly lower power usage.

Better CoreLocation Pattern Options

The first issue to tackle when implementing CoreLocation features is how to create your own manager that can be used and called throughout the app. The second issue that has to be addressed is how to allow other classe, regardless of type, UIView, UIViewController, NSObject, get notified of updated location information.

Issue One

The basic approach is to create subclass of NSObject that conforms to CLLocationManagerDelegate and implements the appropriate delegate methods. In my particular case I do have to listen for a stream of updates so I will be setting the desiredAccuracy and distanceFilter properties.

Issue Two

In order to tackle issue 2 I go one of three ways: NSNotification, Target/Action or KVO.

NSNotification would solve this problem, however it is seemed too decoupled and I personally feel that NSNotifications should be reserved for OS level notifications not service layer/domain model context changes. Finally, there are performance considerations when it comes to using notifications. No matter if the post to the notification center is done asynchronously or synchronously it is dispatched to the object synchronously. If there are a number of observers or if there is an instance where an observer must do a lot of work then your app could experience a significant delay.

Next on the list is the target/action pattern. While NSNotification was too decoupled from listeners, using target/action has now added a level of coupling that I felt a little unnecessary. In our custom manager class I would have to set a property, either NSMutableArray, NSSet or id that would hold the target instance, in addition, a property for the SEL, and when the location manager’s delegate method received a valid location update I would have to call something like:

`//NSMutableArray or NSSet

[clmListeners makeObjectsPerformSelector:@selector(methodToPerform)];`

`//id target

[target performSelector:@selector(methodToPerform)]`

There are two issues with doing the above proposal:

  1. You have the manager class now responsible for another class’s implementation without a contract.

  2. You are getting really close to having a delegate pattern which brings us closer to a one-to-one coupling between our classes.

The final option that we come to is Key Value Observing…which is the solution that I have gone with. Not only does it keep our manager class independent, but we also are also able to write our location code once while allowing our other classes to handle any UI or model manipulation as they see fit…independent of any other implementation or logic.

Custom Core Location Manager Class

gist.github.com/2421914

View Controller Observing Change to Current Location

gist.github.com/2421928