Mobile10 minute read

An iOS Developer’s Guide: From Objective-C to Learning Swift

After 6 years of improving and working on Objective-C, Apple decided to throw another challenge at developers. Once again, iOS developers will need to learn a new programming language: Swift.

Swift 1.0 is already a stable and strong development platform, which is sure to evolve in interesting ways over the coming years. It is a perfect moment to start exploring this new language, as it is the future of iOS development.


Toptalauthors are vetted experts in their fields and write on topics in which they have demonstrated experience. All of our content is peer reviewed and validated by Toptal experts in the same field.

After 6 years of improving and working on Objective-C, Apple decided to throw another challenge at developers. Once again, iOS developers will need to learn a new programming language: Swift.

Swift 1.0 is already a stable and strong development platform, which is sure to evolve in interesting ways over the coming years. It is a perfect moment to start exploring this new language, as it is the future of iOS development.


Toptalauthors are vetted experts in their fields and write on topics in which they have demonstrated experience. All of our content is peer reviewed and validated by Toptal experts in the same field.
Marco Mustapic
Verified Expert in Engineering

Marco is a Senior iOS developer specializing in game development with a particular affinity for coding conceptually original apps.

PREVIOUSLY AT

Gameloft
Share

In 2008 Apple announced and released the iPhone SDK 2.0. This event started another revolution in software development, and a new breed of developer was born. They are now recognized as iOS developers.

Many of these developers had never used Objective-C before, and that was the first challenge Apple threw at them. Despite unfamiliar syntax and manual memory management, it was immensely successful, helping populate the App Store with tens of thousands of apps. Apple continually improved Objective-C with each release, adding blocks and literals, simplified memory management with automatic reference counting, and many other features indicative of a modern programming language.

And after 6 years improving and working on Objective-C, Apple decided to throw another challenge at developers. Once again, iOS developers will need to learn a new programming language: Swift. Swift removes the unsafe pointer management and introduces powerful new features, while maintaining interaction with both Objective-C and C.

Swift 1.0 is already a stable and strong development platform, which is sure to evolve in interesting ways over the coming years. It is a perfect moment to start exploring this new language as it is obviously the future of iOS development.

The purpose of this tutorial is to give Objective-C developers a quick overview of new Swift language features, helping you take the next step and begin adopting Swift in your everyday work. I will not spend too much time explaining Objective-C, and I will assume you are familiar with iOS development.

Swift changed the game for Objective-C iOS developers.

Trying out Swift vs. Objective-C

In order to start exploring Swift all you need to do is download XCode from the App Store and create a playground to experiment. All examples mentioned in this article are done this way.

Apple’s Swift homepage is the best reference for learning Swift programming. You will find it to be invaluable, and until you are fully up to speed with Swift development I believe that you will come back here often.

Variables and Constants

Declaring a variable in Swift is done using the var keyword.

var x = 1
var s = "Hello"

You will notice that two variables x and s are of different types. x is an Integer, while s is a String. Swift is a type safe language, and it will deduce variable types from the assigned value. If you wish to make your code more readable you can optionally annotate the variable’s type:

var y: Int
y = 2

Constants are similar, but you declare them using let instead of var. The value of a constant doesn’t need to be known at compile time, but you must assign it a value exactly once.

let c1 = 1 // Constant known at compile time

var v = arc4random()
let c2 = v // Constant known only at run time 

As their name suggests, they are immutable, so the following code will cause a compile-time error.

let c = 1
c = 3        // error

Other types can also be declared as constant. For example, the following code declares an array as a constant, and if you attempt to modify any of the elements, the Swift compiler will report an error:

var arr2 = [4, 5, 6]
arr2[0] = 8
print (arr2)    // [8, 5, 6]

let arr = [1, 2, 3]
a[0] = 5    // error

Optionals

Constants need to be initialized when declaring them, and variables need to be initialized before use. So where’s the Objective-C nil equivalent? Swift introduces optional values. Optional values can have a value or be nil. If you take a look at the following code, you will notice that x was assigned an Optional value of 2014. This means that Swift compiler was aware that x might also be nil.

var s = "2014"
var x = s.toInt()
print(x)    // Optional(2014)

If you make a change in this code and assign the value "abc" to s, which cannot be converted to an Integer, you will notice that x is now anil.

var s = "abc"
var x = s.toInt()
print(x)    // nil

The return type of toInt() function is Int?, which is an optional Int. Let’s try to call a standard function on x:

var x = "2014".toInt()
print(x.successor()) // error

The compiler signals an error, since x is an optional and could potentially be nil. We have to test x first, and make sure that the successor function is invoked on a real number, and not a nil value:

var x = "2014".toInt()
if x != nil
{
  print(x!.successor())    // 2015
}

Note that we have to unwrap x by appending an exclamation mark (!). When we are sure that x contains a value, we can access it. Otherwise we will get a runtime error. We can also do what Swift calls optional binding, converting the optional into a non-optional variable

let x = "123".toInt()
if let y = x
{
  print(y)
}

The code in the if statement will only execute if x has a value, and assign it to y. Note that we don’t need to unwrap y, it’s type is not optional since we know x is not nil.

Check Apple’s Swift tutorial to read more details on optionals and nice features like optional chaining

String Interpolation

In Objective-C formatting strings is usually done with the stringWithFormat: method:

NSString *user = @"Gabriel";
int days = 3;
NSString *s = [NSString stringWithFormat:@"posted by %@ (%d days ago)", user, days];

Swift has a feature called string interpolation to do the same, but it is more compact and easier to read:

let user = "Gabriel"
let days = 3
let s = "posted by \(user) \(days) ago"

You can also use expressions:

let width = 2
let height = 3
let s = "Area for square with sides \(width) and \(height) is \(width*height)"

To learn more about Swift’s string interpolation and other new features, go here.

Functions

Function definition in Swift is different from C. A sample function definition is below:

func someFunction(s:String, i: Int) -> Bool
{
    ...    // code    
}

Swift functions are first-class types. This means that you can assign functions to variables, pass them as parameters to other functions, or make them return types:

func stringLength(s:String) -> Int
{
    return countElements(s)
}

func stringValue(s:String) -> Int
{
    if let x = s.toInt()
    {
        return x
    }
    return 0
}

func doSomething(f:String -> Int, s:String) -> Int
{
    return f(s).successor()
}

let f1 = stringLength
let f2 = stringValue

doSomething(f1, "123")    // 4
doSomething(f2, "123")    // 124

Again, Swift infers the types of f1 and f2 (String -> Int), although we could have defined them explicitly:

let f1:String -> Int = stringLength

Functions can also return other functions:

func compareGreaterThan(a: Int, b: Int) -> Bool
{
    return a > b
}

func compareLessThan(a: Int, b: Int) -> Bool
{
    return a < b
}

func comparator(greaterThan:Bool) -> (Int, Int) -> Bool
{
    if greaterThan
    {
        return compareGreaterThan
    }
    else
    {
        return compareLessThan
    }
}

let f = comparator(true)
println(f(5, 9))

A guide to functions in Swift can be found here.

Enumerations

Enumerations in Swift are much more powerful than in Objective-C. As Swift structs, they can have methods, and are passed by value:

enum MobileDevice : String
{
    case iPhone = "iPhone", Android = "Android", WP8 = "Windows Phone8", BB = "BlackBerry"

    func name() -> String
    {
        return self.toRaw()
    }
}
let m = MobileDevice.Android
print(m.name())    // "Android"

Unlike Objective-C, Swift enumerations can assign Strings, characters or floats as values for each member, besides integers. The convenient toRaw() method returns the value assigned to each member.

Enumerations can also be parameterized:

enum Location
{
    case Address(street:String, city:String)
    case LatLon(lat:Float, lon:Float)
    
    func description() -> String
    {
        switch self
        {
        case let .Address(street, city):
            return street + ", " + city
        case let .LatLon(lat, lon):
            return "(\(lat), \(lon))"
        }
    }
}

let loc1 = Location.Address(street: "2070 Fell St", city: "San Francisco")
let loc2 = Location.LatLon(lat: 23.117, lon: 45.899)
print(loc1.description())        // "2070 Fell St, San Francisco"
print(loc2.description())        // "(23.117, 45.988)"

More information about enumerations is available here.

Tuples

Tuples group multiple values into a single compound value. The values within a tuple can be of any type and do not have to be of the same type as each other.

let person = ("Gabriel", "Kirkpatrick")
print(person.0) // Gabriel

You can also name the individual tuple elements:

let person = (first: "Gabriel", last: "Kirkpatrick")
print(person.first)

Tuples are extremely convenient as return types for functions that need to return more than one value:

func intDivision(a: Int, b: Int) -> (quotient: Int, remainder: Int)
{
    return (a/b, a%b)
}
print(intDivision(11, 3))    // (3, 2)
let result = intDivision(15, 4)
print(result.remainder)    // 3

Unlike in Objective-C, Swift supports pattern matching in a switch statement:

let complex = (2.0, 1.1)    // real and imaginary parts

switch complex
{
    case (0, 0):
        println("Number is zero")
    case (_, 0):
        println("Number is real")
    default:
        println("Number is imaginary")
}

In the second case we don’t care about the real part of the number, so we use an _ to match anything. You can also check for additional conditions in each case. For that we need to bind the pattern values to constants:

let complex = (2.0, 1.1)

switch complex
{
    case (0, 0):
        println("Number is zero")
    case (let a, 0) where a > 0:
        println("Number is real and positive")
    case (let a, 0) where a < 0:
        println("Number is real and negative")
    case (0, let b) where b != 0:
        println("Number has only imaginary part")
    case let (a, b):
        println("Number is imaginary with distance \(a*a + b*b)")
}

Note how we need to bind only the values we are going to use in the comparison or in the case statement.

To read more about tuples, go here.

Classes and Structures

Unlike Objective-C, Swift does not require you to create separate interface and implementation files for custom classes and structures. As you learn Swift, you will learn to define a class or a structure in a single file, and the external interface to that class or structure is automatically made available for other code to use.

Defining Classes

Class definitions are very simple:

class Bottle
{
   var volume: Int = 1000
   
   func description() -> String
   {
       return "This bottle has \(volume) ml"
   }
}
let b = Bottle()
print(b.description())

As you can see, declaration and implementation are in the same file. Swift no longer uses header and implementation files. Let’s add a label to our example:

class Bottle
{
   var volume: Int = 1000
   var label:String
   
   func description() -> String
   {
       return "This bottle of \(label) has \(volume) ml"
   }
}

The compiler will complain because label is a non-optional variable and will not hold a value when a Bottle is instantiated. We need to add an initializer:

class Bottle
{
   var volume: Int = 1000
   var label:String
   
   init(label:String)
   {
       self.label = label
   }

   func description() -> String
   {
       return "This bottle of \(label) has \(volume) ml"
   }
}

Or, we could use Optional type for a property, which does not to be initialized. In the following example we made volume an Optional Integer:

class Bottle
{
   var volume: Int?
   var label:String
   
   init(label:String)
   {
       self.label = label
   }

   func description() -> String
   {
        if self.volume != nil
        {   
               return "This bottle of \(label) has \(volume!) ml"
           }
           else
           {
               return "A bootle of \(label)"
           }
   }
}

Structures

The Swift language also has structs, but they are much more flexible than in Objective-C. The following code tutorial defines a struct:

struct Seat
{
    var row: Int
    var letter:String
    
    init (row: Int, letter:String)
    {
        self.row = row
        self.letter = letter
    }
    
    func description() -> String
    {
        return "\(row)-\(letter)"
    }
}

Like classes in Swift, structures can have methods, properties, initializers, and conform to protocols. The main difference between classes and structures is that classes are passed by reference, while structs are passed by value.

This example demonstrates passing classes by reference:

let b = Bottle()
print(b.description())    // "b" bottle has 1000 ml

var b2 = b
b.volume = 750
print(b2.description())    // "b" and "b2" bottles have 750 ml

If we try similar case with struct, you will notice that variables are passed by value:

var s1 = Seat(row: 14, letter:"A")
var s2 = s1
s1.letter = "B"
print(s1.description())    // 14-B
print(s2.description())    // 14-A

When should we use struct and when should we use class? As in Objective-C and C, use structs when you need to group a few values, and expect them to be copied rather than referenced. For example, complex numbers, 2D or 3D points, or RGB colors.

An instance of a class is traditionally known as an object. However, Swift classes and structures are much closer in functionality than in other languages, and much functionality can apply to instances of either a class or a structure type. Because of this, the more general term used in Swift reference is instance, which applies to any of these two.

Learn the basics of Swift classes and structures here.

Properties

As we saw earlier, properties in Swift are declared with the var keyword inside a class or struct definition. We can also declare constants with a let statement.

struct FixedPointNumber
{
    var digits: Int
    let decimals: Int
}

var n = FixedPointNumber(digits: 12345, decimals: 2)
n.digits = 4567    // ok
n.decimals = 3     // error, decimals is a constant

Also keep in mind that class properties are strongly referenced, unless you prefix them with the weak keyword. However there are some subtleties with weak non-optional properties, so read the automatic reference counting chapter in Apple’s Swift guide.

Computed Properties

Computed properties do not actually store a value. Instead, they provide a getter and an optional setter to retrieve and set other properties and values indirectly.

The following code provides a sample of a computed value sign:

enum Sign
{
    case Positive
    case Negative
}

struct SomeNumber
{
    var number:Int
    var sign:Sign
    {
        get
        {
            if number < 0
            {
                return Sign.Negative
            }
            else
            {
                return Sign.Positive
            }
        }
        
        set (newSign)
        {
            if (newSign == Sign.Negative)
            {
                self.number = -abs(self.number)
            }
            else
            {
                self.number = abs(self.number)
            }
        }
    }
}

We can also define read-only properties by just implementing a getter:

struct SomeNumber
{
    var number:Int
    var isEven:Bool
    {
        get
        {
            return number % 2 == 0
        }
    }
}

In Objective-C, properties are usually backed by an instance variable, declared explicitly or automatically created by the compiler. In Swift, on the other hand, a property doesn’t have a corresponding instance variable. That is, the backing store of a property cannot be accessed directly. Suppose we have this in Objective-C

// .h
@interface OnlyInitialString : NSObject

@property(strong) NSString *string;

@end

// .m

@implementation OnlyInitialString

- (void)setString:(NSString *newString)
{
    if (newString.length > 0)
    {
        _string = [newString substringToIndex:1];
    }
    else
    {
        _string = @"";
    }
}

@end

Since, in Swift, computed properties don’t have a backing store, we need to do something like this:

class OnlyInitialString
{
    var initial:String = ""
    var string:String
    {
        set (newString)
        {
            if countElements(newString) > 0
            {
                self.initial = newString.substringToIndex(advance(newString.startIndex, 1))
            }
            else
            {
                self.initial = ""
            }
        }
        get
        {
            return self.initial
        }
    }
}

Properties are explained in more detail here

To Be Continued

There are many more important new things to learn about in Swift, like Generics, interaction with Objective-C libraries, closures, optional chaining, and operator overloading. A single tutorial cannot describe thoroughly a new language, but I have no doubt much more will be written about learning Swift programming. However, I believe that this quick read will help many Objective-C developers, who haven’t managed to find time and learn details of Swift language, get on track and let the Swift bird take them to a new heights.

Hire a Toptal expert on this topic.
Hire Now
Marco Mustapic

Marco Mustapic

Verified Expert in Engineering

Gent, Belgium

Member since March 1, 2013

About the author

Marco is a Senior iOS developer specializing in game development with a particular affinity for coding conceptually original apps.

authors are vetted experts in their fields and write on topics in which they have demonstrated experience. All of our content is peer reviewed and validated by Toptal experts in the same field.

PREVIOUSLY AT

Gameloft

World-class articles, delivered weekly.

By entering your email, you are agreeing to our privacy policy.

World-class articles, delivered weekly.

By entering your email, you are agreeing to our privacy policy.

Join the Toptal® community.