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.
Top comments (0)