Blog

Swift Tip: Refactoring with Deprecations

During a large refactoring, we often work for a long time without being able to compile and run our code. In last week’s Swift Talk, we factored out a child view controller from a very large view controller, and we tried to avoid this danger by using computed properties and deprecation warnings. Let’s look at an example.

The view controller we were working on — Wikipedia’s places view controller — has many outlets, some of which we wanted to pull out into the new child view controller:

class PlacesViewController: PreviewingViewController /* ... */ {
    // ...
    @IBOutlet weak var listAndSearchOverlayFilterSelectorContainerView: UIView!
    @IBOutlet weak var listAndSearchOverlaySearchBar: UISearchBar!
    // ...
}

In total, we moved about ten outlets from the places view controller into a new child view controller. These outlets are used throughout the places view controller, and removing them breaks a lot of code; without any special measures we would be working for a few hours before the code compiles again. To keep the code compiling, we moved the original outlets to the new view controller and created computed properties in the original view controller:

class PlacesViewController: PreviewingViewController /* ... */ {
    // ...
    var searchViewController: PlacesSearchViewController! // this refers to the new child view controller

    var listAndSearchOverlayFilterSelectorContainerView: UIView! {
        return searchViewController.listAndSearchOverlayFilterSelectorContainerView
    }
    var listAndSearchOverlaySearchBar: UISearchBar! {
        return searchViewController.listAndSearchOverlaySearchBar
    }
    // ...
}

class PlacesSearchViewController: UIViewController {
    // ...
    @IBOutlet weak var listAndSearchOverlayFilterSelectorContainerView: UIView!
    @IBOutlet weak var listAndSearchOverlaySearchBar: UISearchBar!
    // ...
}

To be clear, this is a temporary fix used to make the code compile, not a long-term solution. We want to move all code that depends on these views into the new child view controller, but we want to do it step-by-step.

Now that our code compiles, it’s easy to forget to move code out of the old view controller. To prevent such oversights (and the temptation to stop short of our original goal), we add deprecation annotations to the computed properties:

class PlacesViewController: PreviewingViewController /* ... */ {
    // ...
    @available(*, deprecated) var listAndSearchOverlayFilterSelectorContainerView: UIView! {
        return searchViewController.listAndSearchOverlayFilterSelectorContainerView
    }
    @available(*, deprecated) var listAndSearchOverlaySearchBar: UISearchBar! {
        return searchViewController.listAndSearchOverlaySearchBar
    }
    // ...
}

With these annotations in place, each usage of a computed property shows up both as an inline warning and in the issue navigator — a good reminder of the work we still have to do (and a better reminder than “todo” comments, which are all too easy to ignore!).

If you’d like to follow our refactoring series, the first episode is public.

To see how we progress, become a subscriber.

 

Stay up-to-date with our newsletter or follow us on Twitter.

Back to the Blog

recent posts