Think And Build

iOS

From Objective-C to Swift: thoughts and hints

Posted on .

From Objective-C to Swift: thoughts and hints

Introduction

In this article I want to share with you some of the thoughts I had along the way during my transition from Objective-C to Swift. I’ll try to give you hints and I’ll discuss the main pitfalls, trying to compare, when possible, the different approaches of these two languages. So without further ado let’s dive into the core of the article!

NOTE: this article has been written referring to Beta 2 of Xcode 6.

Single file vs Interface-Implementation files

A first big change that is worth mentioning is the dismissal of the interface.h/implementation.m structure.
I have to admit that I’m a strong supporter of that model; Obtaining and sharing information about a class just via the interface file is safe and quick.

In Swift interface and implementation aren’t split in two files. We just implement our class (and at the time of writing it is not even possible to add visibility modifiers).

There are some caveats that we can use if we really are unable to tolerate this huge change:

The first is obvious: Using common sense.
We can easily enhance readability of our classes with good documentation. For example, we can move the elements we want to be “public” at the top of our file, maybe using an extension just to separate public and private areas.
Another really common choice is to prefix private methods and variables with an underscore “_”.

Here is a short example mixing the two:

[code lang=”Obj-C”]
// Public
extension DataReader {

var data { }
func readData(){
var data = _webserviceInteraction()
}
}

// Private implementation
class DataReader: NSObject {

let _wsURL = NSURL(string: "http://theurl.com")

func _webserviceInteraction()->String{
// …
}
}

Although we can’t modify the visibility of our class elements, we can try to make accessing some of them “more difficult”.
An exotic solution that partially hides private area (at least to the autocomplete) can be achieved using a nested class, here’s an example:

[code lang=”Obj-C”]
import UIKit

class DataReader: NSObject {

// Public ***********************
var data:String?{
get{return private.internalData}
}

init(){
private = DataReaderPrivate()
}

func publicFunction(){
private.privateFunc()
}

// Private **********************
var private:DataReaderPrivate

class DataReaderPrivate {
var internalData:String?

init(){
internalData = "Private data!"
}

func privateFunc (){}
}
}

We put private implementations into the private constant instance and we use the “regular” class implementation just as public interface. The private elements are not really hidden but to access them we have to go through the “private” constant.

[code lang=”Obj-C”]
let reader = DataReader()
reader.private.privateFunc()

The question is: is this weird pattern worth the final goal of partially hiding the private elements?
My suggestion is to wait for visibility modifiers (Apple is working on it) and in the meanwhile just use good documentation with or without extensions.

Constants and Variables

In Objective-C I’ve rarely used the const keyword, even when I knew that some data would never change (OK… shame on me). With Swift, Apple suggest developers to give some more thought to the choice of using a constant (let) instead of a variable (var). So just keep an eye on it and try to figure out the effective role of your variables. You’ll end up using more constants than you’d expect.

Write only what needs to be written

Look at these 2 rows of code and find the differences:
[code]
let wsURL:NSURL = NSURL(string:"http://wsurl.com");
vs
let wsURL = NSURL(string:"http://wsurl.com")

During the first 2 weeks of training with Swift I forced myself to remove semicolons from the end of each line of my code. My life is better now (and now I forget to add semicolons in Objective-C :|)

Type inference is the ability to assign a type to a variable, inferring it directly from its definition. This is another convenience that turns out to be a bit hard to embrace, when coming from a verbose language like Objective-C.
We should try to use consistent methods naming, otherwise it would be difficult for another developer (and for you) to guess the type inferred by an unfortunate naming choice:

[code lang=”Obj-C”]
let a = something()

A more reasonable name helps us:
[code lang=”Obj-C”]
let a = anInt()

Another big change is the use of parenthesis. They are no longer required.
[code lang=”Obj-C”]
if (a > b){}
vs
if a > b {}

But remember, what we write between the parenthesis is evaluated as an expression and we are not always allowed to write it that way. In variable binding, for example, we can’t use parenthesis:

[code lang=”Obj-C”]
if (let x = data){} // Error!
if let x = data {} // OK!

We are not required to adopt type inference or to remove semicolons and parentheses but we can consider these choices as the suggested ways to write code in Swift. We’ll end up enhancing readability and saving some keyboard typing.

Optionals

How many times, working with functions that return “a value” or “nothing”, did you wonder what the best way to define “nothing” was? I’ve used NSNotFound, -1, 0, custom return values…
Thanks to Optionals we now have the “nothing-value” completely defined, we just need to add a question mark after the data type.

We can write:

[code lang=”Obj-C”]
class Person{
let name:String
let car:Car? // Optional value

init(name:String){
self.name = name
}
}

// ACCESSING THE OPTIONAL VALUE ***********

var Mark = Person(name:"mark")

// use optional binding
if let car = Mark.car {
car.accelerate()
}

// unwrap the value
Mark.car?.accelerate()

In this example the relation “Person has a Car” is defined by an Optional. It means that the car property can be nil, a Person could not have a car.
Then we access this value using optional binding (if let car = ) or using unwrap (car?).

If we don’t define a property as optional we are required to set a value for that property or the compiler will soon complain.
Our last chance to define a non optional property value is within an initialiser.
So we are required to determine how the class properties will interact with the rest of the class and how they will behave during class instances existence.
These improvements completely change the way we conceive our classes.

Optionals unwrapping

If you find it difficult to work with optionals because you can’t understand why the compiler asks you to unwrap a value before using it…
[code lang=”Obj-C”]
Mark.car?

…I suggest you to think about an Optional as a struct (it is a struct, so it shouldn’t be too difficult 😛 ) that doesn’t contain your value directly, but adds a layer around it (wrap). If the internal value is defined, you remove the layer (unwrap) and you get the wanted value, otherwise you get nil. BOOM.
Forcing the unwrap through the “!” sign is just a way to remove the layer without caring about the internal value. You “risk” trying to access a value behind the layer. If this value is nil the application just crashes.

Delegate pattern

After years spent coding with Objective-C and Cocoa we are delegate pattern addicted.
Fear not! We still adopt that pattern the same way we were used to. Here’s a super simple example of a delegate:

[code lang=”Obj-C”]

@objc protocol DataReaderDelegate{
@optional func DataWillRead()
func DataDidRead()
}

class DataReader: NSObject {

var delegate:DataReaderDelegate?
var data:NSData?

func buildData(){

delegate?.DataWillRead?() // Optional method check
data = _createData()
delegate?.DataDidRead() // Required method check
}
}

We substitute the check for delegate existence and the use of respondToSelector with an elegant optional chaining.

[code lang=”Obj-C”]
delegate?.DataWillRead?()

Note that we have to prefix protocol with the @obj keyword because we used @optional. By the way, the compiler will warn us with a clear message in case we forgot it.

To implement this delegate we implement the protocol into another class and we assign it as we were used to with Objective-C:

[code lang=”Obj-C”]
class ViewController: UIViewController, DataReaderDelegate {

override func viewDidLoad() {
super.viewDidLoad()

let reader = DataReader()
reader.delegate = self
}

func DataWillRead() {…}

func DataDidRead() {…}
}

Target Action Pattern

Another common pattern that we still use in Swift is the target-action and even in this case we implement it the same way we did in Objective-C.

[code lang=”Obj-C”]
class ViewController: UIViewController {

@IBOutlet var button:UIButton

override func viewDidLoad() {
super.viewDidLoad()

button.addTarget(self, action: "buttonPressed:", forControlEvents: UIControlEvents.TouchUpInside)
}

func buttonPressed(sender:UIButton){…}
}

The only real difference is how we define a selector. We just write the method prototype using a String that will be automatically converted in something like:

[code lang=”Obj-C”]
Selector("buttonPressed:")

Singleton pattern

Love it or hate it, the singleton is still one of the most adopted patterns out there.

We can implement it using GDC and dispatch_once or we can just rely on the thread-safe nature of the let keyword.

[code lang=”Obj-C”]
class DataReader: NSObject {

class var sharedReader:DataReader {

struct Static{
static let _instance = DataReader()
}

return Static._instance
}

}

Let’s have a quick look at this code.
1. SharedReader is a static compound property (we can substitute this implementation with a function)
2. Static (not compound) properties are not yet allowed into a class implementation. So thanks to nested types we add a nested struct to the class.
A struct supports Static properties, so we just add the static property here.
3. The _instance property is a constant. It can’t be overridden with another value and it is thread-safe.

We can refer to the singleton instance of DataReader using:
[code lang=”Obj-C”]
DataReader.sharedReader

Struct and Enum

In Swift, struct and enums have a lot of features that you hardly find implemented in other languages.

They support methods:
[code lang=”Obj-C”]
struct User{
// Struct properties
let name:String
let ID:Int

// Method!!!
func sayHello(){
println("I’m " + self.name + " my ID is: \(self.ID)")
}
}

let pamela = User(name: "Pamela", ID: 123456)
pamela.sayHello()

As you can see the struct uses an initializer, that in this case is automatically created by Swift (we could add other custom implementations).

The enum syntax is a bit different by the syntax we are used to.
It defines its cases using the keyword case:
[code lang=”Obj-C”]
enum Fruit {
case orange
case apple
}

Enum is not limited to int values:
[code lang=”Obj-C”]
enum Fruit:String {
case .orange = "Orange"
case .apple = "Apple"
}

and we can build an enum with a more complex behaviour:
[code lang=”Obj-C”]
enum Fruit{

// Available Fruits
case orange
case apple

// Nested type
struct Vitamin{
var name:String
}

// Compound property
var mainVitamin:Vitamin {

switch self{
case .orange:
return Vitamin(name: "C")

case .apple:
return Vitamin(name: "B")
}
}
}

let Apple = Fruit.apple
var Vitamin = Apple.mainVitamin

In the previous code we added a nested type (Vitamin) and a compound property (mainVitamin) that initializes elements for that struct depending on the enum value. Mind blowing… isn’t?

Mutable and Immutable (and fixed bug!)

With Objective-C we are used to immutable and mutable versions of whatever class. Some examples? NSArray and NSDictionary.
With Swift we don’t need different data types anymore, we just leverage on constant or variable definition.
A variable Array is mutable while with a constant Array we can’t change its stored values. So just keep in mind the rule “let = immutable. var = mutable” (Fixed Bug: before Beta 3 you could modify a let Array).

Blocks vs Closures

I love the syntax for Blocks, it’s so clear and easy to remember! [code]</IronicMode>

By the way, after some years of development with Cocoa, we get used to this syntax and sometimes I prefer to substitute easy delegation tasks with blocks. They are ingenious, quick and totally useful.
The Swift counterparts of Blocks are Closures. The power behind Closures is extreme and Apple did a great job trying to simplify the way we write them.
The example on the official Swift documentation leaves me speechless.
It starts from this definition
[code]
reversed = sort(names, { (s1: String, s2: String) -> Bool in
return s1 > s2
})

and it refactors it to:

[code lang=”Obj-C”]
reversed = sort(names, >)

So we have different ways to implement a Closure thanks to type inference, shorthand arguments ($0, $1) and direct operator functions (>).
In this article I’m not going through the Closure syntax but I want to spend some words on capture values within a Closure.
In Objective-C we define a variable as __block when we intend to modify its value trough a Block. Using Closures this becomes unnecessary.
We can access and modify any value of the surrounding scope. In fact Closures are clever enough to capture external elements that are used into the Closure. An element is captured as copy or as reference. If the Closure modifies the value of the element it creates a reference, if not, it creates a copy.

If a Closure refers to the instance that contains/uses the Closure itself we could run into a strong reference cycle

Let’s check this example:

[code lang=”Obj-C”]
class Person{

var age:Int = 0

@lazy var agePotion: (Int) -> Void = {
(agex:Int)->Void in
self.age += agex
}

func modifyAge(agex:Int, modifier:(Int)->Void){
modifier(agex)
}
}

var Mark:Person? = Person()
Mark!.modifyAge(50, Mark!.agePotion)
Mark = nil // Memory Leak

The agePotion closure (damn D&D!) uses self, keeping a strong reference to the current instance. At the same time that instance keeps a reference to the Closure… BOOM… strong reference cycle!

To avoid this problem we use a Capture List. This list associates a weak or unowned reference to the instance that we want to use into the Closure. The syntax is really simple, just add [unowned/strong self] before the Closure definition and the instance will get an unowned/weak reference instead of a strong one.

[code lang=”Obj-C”]
@lazy var agePotion: (Int) -> Void = {
[unowned self](agex:Int)->Void in
self.age += agex
}

Unowned and weak reference

We already know how the weak reference works in Objective-C. It works the same way in Swift, no changes here.
So what about the unowned reference? I’ve really appreciated the introduction of this keyword because it’s a good hint to define relations between classes.

Let’s describe a simple relation between a Person and its BankAccount:
1. A Person can have a BankAccount (optional)
2. A Bank account should belong to a Person (required)

[code lang=”Obj-C”]
We can describe this relation with code:
class Person{
let name:String
let account:BankAccount!

init(name:String){
self.name = name
self.account = BankAccount(owner: self)
}
}

class BankAccount{
let owner:Person

init(owner:Person){
self.owner = owner
}
}

These relationships are going to create a reference cycle. The first solution would be adding a weak reference to the “BankAccount.owner” property. However using an unowned reference we are defining another useful constraint: the property must always have a value, it can’t be nil (we have satisfied the point 2 of the previous list this way).

There is really nothing more to say about the unowned reference. It works exactly like a weak reference without incrementing the counter for the reference it points to, but ensuring a value different from nil.

Final thoughts

I have to admit: sometimes I still run into compiler errors and end up looking at them in silence, just wondering: “WAT?”

The more I work with Swift though, the clearer it becomes it’s worth every hour I’m spending on experiments and learning. There are a lot of interesting changes from Objective-C and things that didn’t exist before that make me want to practice more and get completely comfortable with it.

It’s a welcome breath of fresh air in iOS / OSX development and I’m sure you’re going to love it too!

Ciao

Yari D'areglia

Yari D'areglia

https://www.thinkandbuild.it

Senior iOS developer @ Neato Robotics by day, game developer and wannabe artist @ Black Robot Games by night.

Navigation