DEV Community


Porting to Swift? Do it Gradually Using Extensions: Part 1

Evan Deaubl
A 20-year software generalist who has worked on everything from mobile apps to webapps to backend to embedded.
Originally published at ・4 min read

Despite the fact that Swift has been available to iOS developers for over 4 years now, it’s likely that many long-lived apps still have Objective-C code in them. To keep things up to date, and to take advantage of the more modern Swift language, you will need to port those at least some of those classes to Swift.

You are instantly drawn to your small, simple classes, and you think, “Sure, those won’t be a problem at all. I could knock these out in a couple hours a piece.”

But then you open up one of your large classes. And you freeze.

You know which one. Every codebase has (at least) one. It is one of the core classes of the app: hundreds (or thousands…) of lines of code, many dependencies on other classes in your codebase. It’s a core part of the app; porting this class and testing that the porting doesn’t completely break everything else could takes weeks. Nobody has time for “weeks” anymore.

So you surrender, and those big, hairy Objective-C classes stay big, hairy Objective-C.

It saves unnecessary rework to only refactor code that you are actually changing for another reason. But if you’re only changing one method, you don’t want to port the rest of the class you aren’t touching, because it means extra coding work, extra testing work, extra review work...

Is there a way to port Swift like this, method by method, property by property? There is, by writing Swift extensions for your Objective-C classes.

Extensions allow you to create a separate block of code that extends an existing class definition with additional methods. You can use this feature to gradually port your Objective-C code over to Swift with minimal disruption. The following process comes straight from a porting effort I am doing for one of my own apps, a bowling score tracker called 12 Strikes.

First, if this is the first time you are porting a particular class, you’ll need to create a new Swift file for that class’s extension, the standard way you would create a new Swift file in Xcode. Afterwards, if your Swift code will need to reference UIKit, add import UIKit to the top.

Once you have your .swift file, add the empty extension definition:

extension BowlingGame {

You should already have a Your Project-Bridging-Header.h, either from the previous step earlier, or from earlier porting efforts. If not, follow these instructions to create one manually. Once you have one, add the matching Objective-C .h file for the class you’re porting, so that Swift can reference anything from the base Objective-C class:

#import "BowlingGame.h"

Now you can get down to porting your method. First, comment out the Objective-C method: both the code definition in the .m file and the declaration in the .h file.

At this point, take a breath and let Xcode rebuild your project. Did your compile succeed without errors? If so, this is a strong indicator that you don’t need to port this code, you just need to delete it. Don’t port it if you’re not using it.

If you did get compile errors as you should have, now rewrite your method inside your Swift extension. Be sure to apply the @objc modifier to the method definition so that the method is accessible from Objective-C:

@objc public static func scoreFrame(firstRoll: String, secondRoll: String) -> Int

If you have unit tests for this method, you could rewrite those as well, but I recommend against it. You’re trying to rewrite as little as possible at one time. If you do feel the urge to rewrite the tests as well, rewrite them after you have ported the method to Swift and made sure the Swift method passes all of the Objective-C tests. Objective-C tests will be able to test your ported Swift method.

Finally, if you have Objective-C methods that are dependent on the ported Swift method, then you will also need to add an #import to import Swift declarations into any .m or .h files that reference it:

#import "Your_Project-Swift.h"

Once you have ported the method, you can run the app as a sanity check that you ported the code correctly (especially if you didn’t have unit tests…), and once you’re satisfied, remove the commented out Objective-C version.

Done! From there, it’s simply repeat until the entire class is ported. Although probably not right away. Remember, only port code that you’re changing!

Now the fine print:

Many classes will port this easily, but there are some special cases which require some special techniques in order to port from Objective-C to Swift in a method-by-method manner: using advanced Swift data structures, and UIKit. I will cover those in parts 2 and 3 of this series at Apps Dissected. Sign up for the newsletter to be notified when those parts come out.

Did you like this tip? Part 2 of this series on incremental Swift porting is already waiting for you. Or sign up to get every tip straight to your inbox.

This post originally published at Apps Dissected.

Discussion (0)