Porting from Objective-C to Swift

May was a super busy month, so nothing got published. I have been writing a couple of articles, they are coming, but I’m not completely satisfied with them. So in the mean time I have a little piece regarding porting.

I don’t like to mix sweet and salt flavors, so a chocolate bar sprinkled with sea salt and hot pepper is not my kind of stuff, not even a PBJ sandwich. Jam is great, same with peanut butter, but I can’t stand the mix. Same with my iOS projects. They all are written in Objective-C or Swift, not both.

On this project I’m working on at the moment, I was searching for a different way of pointing out some spots on some graphics. The points in the graphics where very small, and hard to see when picking them, so I thought of the loupe in iOS when selecting text. An effect like that would be perfect. So instead of writing it myself, I searched the inter-webs and found an open sourced project doing exactly what I wanted. Its called iOS-MagnifyingGlass, written by Arnaud Coomans.

I really wanted a Swift version of these classes, so I decided to do something I have done a lot lately; Porting from Objective-C to Swift.

First of all, you should take a quick peek over at GitHub so you are familiar with the Objective-C classes. There is no need to study them in detail, but you should have some understanding in how they are organized. In the code sections below, all Objective-C code are marked with Objective-C, as well all lines end with a semicolon. The Swift code has no semicolon, and the code sections are marked with Swift as well.

After checking them out, the main two classes I was interested in where ACMagnifyingView containing the area you want to magnify and methods for moving the loupe, and ACMagnifyingGlass, drawing the loupe itself, and methods for enlargement. I created two UIView sub classes in Swift, and gave them the same names as the Objective-C classes.

The ACMagnifyingView header file contains two properties. Since the properties defined in the header are available to other classes, I consider them public properties. These I copied to my Swift counterpart.

After “Swiftifying” these lines, they became:

Turning the attention to the ACMagnifyingView implementation file, it also has some properties defined, and since only the header files are exposed to other classes in Objective-C, the properties in the .m file could be treated as private properties.

Constants are also by default immutable, so this one is really easy.

For clarity I use my own standard prefix YP on the constant name.

Here a mutable property was defined, as well as some of the methods used in this class. The methods will be taken care of a little bit later, so I just put the touchTimer property in the Swift file.

A couple of lines down I found some synthesized variables

The lines with @synthesize  automatically creates property variables and their setters and getters in Objective-C. I had already defined them in the Swift file, so for now the properties was done.

The complete Swift file should look like this at this point

Since I wanted to use my own prefix on the classes, I had to change the AC prefix to YP. I also prefer to use as little conversion between variables as possible, so I changed the MagnifyingViewDefaultShowDelay constant from being a CGFloat to a NSTimeInterval.

Now its time to start with the functions. Here I define all functions defined in the Objective-C header file together with the init functions as public. Also the Touch Events have to be in the same state as the class itself, and since the class is public, all Touch Events are public as well.

Instead of showing the magnifying glass for each and every touch of the screen, and easily separate intended from unintended touches, the instantiation of the magnifying glass object is called after a delay. Therefor the addMagnifyingGlassTimer function has to be public as well, or the delayed call will crash. Thats why some of the functions in the ported class are public instead of private as in the original Objective-C version.

Now the rest of our functions in this class can be private.

As you can see, each line is almost identical with the Objective-C version, there are only minor differences. The trick is to paste the Objective-C methods into the Swift file, and then change

- (void)methodName:(Type)parameterName 

into

func methodName(parameterName: Type) 

If a method returns a type of data, the conversion is like this

- (returnType)methodName:(Type)parameterName

into

func methodName(parameterName: Type) -> returnType

Now the porting of the first class is completed. The second one I will demonstrate in a little screen cast. The main trick is to use the compiler errors for what its worth. Checking line by line up against the documentation makes it really easy to make the errors go away.

After the code is roughly ported, you have to go through it optimizing and checking all properties and variables. This was a quick and dirty port, it works, and after some more tweaking, it will be as great in Swift as in Objective-C.

The final code can be downloaded from GitHub as soon as I have gotten the proper credits figured out with Arnaud Coomans.

Update: Arnaud gave me permission to share my port with you all. Get it from GitHub.