TrainingPeaks iOS app

3 Tips for Modernizing your iOS codebase

Charlie Bartel
TrainingPeaks Product Development

--

The much loved TrainingPeaks iOS app is over two years old. The original code was written in Objective-C, most of the views are using frame based layouts, and the app originally targeted iOS 6. So how do we modernize the code-base while still hitting critical business needs for new features? How do we convert the code-base from Objective-C to Swift and provide real value to the customer in the process? The blueprint for successfully modernizing our iOS app follows.

1) Go Vertical with Swift

Many of us are faced with apps written entirely in Objective-C. We want to transition to Swift but how do we make the transition safely and still meet deadlines? Rene Cacheaux recently addressed this topic at the 360iDev conference. Based on his real life experiences, he recommends identifying new and existing vertical slices of code to write in Swift.

Slide from Rene Cacheaux, Blue is Objective-C, Orange is Swift

Why vertical instead of horizontal? Rene believes we won’t maximize our use of Swift if we go horizontal. We want to avoid Objective-C code consuming Swift code or we will design for the least common denominator. He points out only a portion of Swift features are available to Objective-C.

Slide from Rene Cacheaux, Swift features that are accessible and not accessible to Objective-C

2) Set Deployment Target to iOS 8

According to Apple, 86% of devices are running iOS 8. For the TrainingPeaks app, that number is over 92% according to Google Analytics so we have decided to drop support for iOS 7. That will allow us to utilize the APIs introduced in iOS 8. The big changes in UIKit for our codebase are:

  • The new UIAlertController class replaces the UIActionSheet and UIAlertView classes as the preferred way to display alerts in your app.
  • The UISearchController class replaces the UISearchDisplayController class for managing the display of search-related interfaces.
  • The UIViewController class adopts traits and the new sizing techniques for adjusting the view controller’s content.

This article from NSHipster helps with transitioning to the new UIAlertController class.

The new sizing techniques for UIViewControllers means that in iOS 8, the old methods for interface rotation are deprecated. In some ways the new technique for handling rotations is more coherent, rotation is now simply treated as a bounds change. But updating your entire app for the new APIs is no small task. An elegant approach for migrating all your UIViewControllers to the replacement methods is discussed on Stack Overflow.

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];

// Code here will execute before the rotation begins.
// Equivalent to placing it in the deprecated method -[willRotateToInterfaceOrientation:duration:]

[coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) {

// Place code here to perform animations during the rotation.
// You can pass nil or leave this block empty if not necessary.

} completion:^(id<UIViewControllerTransitionCoordinatorContext> context) {

// Code here will execute after the rotation has finished.
// Equivalent to placing it in the deprecated method -[didRotateFromInterfaceOrientation:]

}];
}

UITableViews also benefit from iOS 8 — self-hiding navigation bars and auto-sizing tableview cells modernize the look and feel of lists.

// When the user swipes the navigationBar will be hidden
self.navigationController.hidesBarsOnSwipe = YES;
self.tableView.rowHeight = UITableViewAutomaticDimension;

The self sizing cells allow the app to easily support text size changes by the user, named Dynamic Type by Apple. Over the past few months, we have had several users request support for Dynamic Type throughout the app. SmileyBorg has a great sample project that demonstrates these new techniques.

Dynamic Type

3) Responsive UI design

Responsive design for iOS is an approach for creating screens that respond to changes in screen size, device orientation and text size. Auto Layout makes it easier to create responsive views for iOS. Contrary to popular opinion, Auto Layout can be done programmatically outside of Interface Builder and Storyboards.

We have found that Storyboards are great for smaller projects with one developer. As Storyboards get large they quickly become confusing and are slow to load. Storyboards make working on a team harder because peer reviewing a storyboard change is nearly impossible and resolving merge conflicts can be a disaster. We have also found that Storyboards hinder code reuse and are hard to refactor. Apple introduced Storyboard References in iOS 9 to alleviate some of these issues but many remain. Further discussion on the pros/cons of Storyboards can be found on StackOverflow.

PureLayout is a great alternative to Apple’s Visual Format Language when doing Auto Layout programmatically. We have found the PureLayout API simple and powerful for converting our frame-based layout code for UIViews and TableView cells.

[self.durationLabel autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:self.titleLabel withOffset:10];[self.durationLabel autoPinEdgeToSuperviewEdge:ALEdgeRight withInset:kLabelHorizontalInsets];

Further the UIStackView class, introduced in iOS 9, gives us a simple programmatic way to horizontally or vertically stack views. Luckily the OAStackView project back-ports this functionality to earlier iOS versions.

UIStackView properties

Split Screen Multitasking, introduced in iOS 9 increases the importance of adopting Auto Layout. In Split View, the user controls the size of your app window. The size of views should be allowed to pass down the view hierarchy — from parent to child to grandchild.

The bounds of the main UIScreen should no longer be used to size views in your app. Methods like [UIScreen mainScreen].bounds.size can not be trusted to determine view size because the app may not be filling the entire screen.

UIInterfaceOrientation is also no longer reliable because your app could be running in split view mode in landscape orientation but have a size that is larger in the vertical direction. To check whether your interface is truly portrait or landscape you can manually compare the width to the height of the visible view controller. All the uses of statusBarOrientation throughout your app should be removed.

iOS 9 Split View

Summary

Modernizing code is a continuous process. We will be doing this same process next summer — dropping iOS 8 for 9 and integrating the new stuff from Apple’s announcement of iOS 10. Our goal is to have 50% of the code-base transitioned to swift by next June, and then get the remaining 50% converted the following year. What is the alternative? A code-base that slowly rots and after a few years has to be completely thrown away because of the insurmountable technical debt. A better path forward is to strategically identify candidates for rewrite and conquer them one at a time.

--

--