Essential Swift for Objective-C Programmers

In this tutorial we will aim to learn essential parts of the Apple's Swift programming language in order to start programming iOS applications with it. The aim of this tutorial is not to learn every feature of the language. Syntax and features wise Swift is a much bigger language compared to Objective-C. In this first part we will explore the syntax of Swift which is more or less parallel to the constructs which are provided in Objective-C. In a later tutorial we will explore more advanced features of Swift.

To explain the core syntax better we will develop a command line OS X Application.

Creating the project

  • Using XCode, start a new project. Under OS X Application Category, choose Command Line Tool.
  • For the product name, provide SwiftExamples and choose Swift as the language.

This should create a project, with a main.swift file, which contains only a "Hello, World" print statement.

You can also to download the source code for this example .

Define a class

Let's create a class. Right click on the SwiftExamples folder and choose "New File". Then choose "Swift File" under Mac OS X Source category. Name it as Rect.swift

Edit the file so that it loos like the following:

File: SwiftExamples/Rect.swift

import Foundation

class Rect {
    
    var height: Int = 0;
    var width = 0
    
}
  • Unlike Objective-C, Swift allows you declare and define a class in a single .swift file.
  • The first line imports the Foundation framework.
  • To create a class, you use the keyword class . In the above example, we have created the class Rect and added 2 properties to it: height and width .
  • As you can see from the code, semicolons are optional. The preferred style is to omit the semicolons if they are not required.
  • A variable is declared with keyword var . To specify the type of the variable, you can insert a : and then mention the variable type after that.
  • When you are immediately assigning a value to the variable, then specifying the type of the variable is not required as the complier can detect the type of the variable from the assigned value. As a stylistic preference, the variable type should not be mentioned if it is evident from the assigned value.
  • Please note that Swift is a statically typed language. It's not a dynamically typed language like PHP or JavaScript, in which you can assign values of different types to the same variable.
  • Also note that unlike many other programming languages, the even primitive type names start with capital letters, for example, Int .

Now open 'main.swift' and remove the print 'Hello, World' statement and make it look like the following:

File: SwiftExamples/main.swift

import Foundation

var rect = Rect()
  • Here we have created one object from the class Rect . Please note that unlike Java or PHP, you don't use the keyword new to instantiate a class.

Now let's add a describe method to the Rect class.

File: SwiftExamples/Rect.swift

import Foundation

class Rect {
    
    ...
    
    func describe() {
        print("Rect - Height: \(height) Width: \(width)")
    }
    
}
  • To define a function, you need to use the keyword func .
  • Here we are using the String Interpolation to substitue the variable values in the string.

Now add the following line in the main.swift file.

File: SwiftExamples/main.swift

...

rect.describe()

Run the program.

output:

Rect - Height: 0 Width: 0

Now add the following line in the main.swift file and run the program.

File: SwiftExamples/main.swift

...

rect.height = 30
rect.width = 30
rect.describe()

output:

Rect - Height: 0 Width: 0
Rect - Height: 30 Width: 30

Inheritance

Let's say that we want to create a Shape class which will be the parent class for all the shapes. So we want to extend the Rect class from the Shape class. Create a new file Shape.swift file in your project and add the following code in it.

File: SwiftExamples/Shape.swift

import Foundation

class Shape {

    func describe() {
        print("The shape has no properties yet.")
    }
}

Then modify your Rect.swift file so that it looks like the following:

File: SwiftExamples/Rect.swift

import Foundation

class Rect: Shape {
    
    var height: Int = 0;
    var width = 0
    
    override func describe() {
        print("Rect - Height: \(height) Width: \(width)")
    }
}
  • Here to extend the Rect class from the Shape class, we have append the : Shape on the class declaration line.
  • Also since we are overriding the describe function in the Rect class we need use the keyword override while providing the definition of the describe() method.

Append the following to your main.swift file.

File: SwiftExamples/main.swift

...

var shape = Shape()
shape.describe()

var rect1 = Rect()
rect1.describe()

output:

...
The shape has no properties yet.
Rect - Height: 0 Width: 0

Methods and Functions

  • Swift allows stand alone functions outside classes. So you can mix procedural as well as object oriented code. In this tutorial we will focus on instance and class methods.

Methods that return value

Let's add an area method to the Rect class.

File: SwiftExamples/Rect.swift

import Foundation

class Rect: Shape {

    ...
    
    func area() -> Int {
        return width * height
    }
}

File: SwiftExamples/main.swift

...

var rectArea = rect.area()
print("Rect area is: \(rectArea)")

output:

...
Rect area is: 900

Methods with parameters

Since Swift is designed to be compatible with Objective C, it supports external parameter names. However Swift uses round brackets to specify the parameters to the functions, so rules to specify external parameter names are a little convoluted in Swift. The main rule to remember is:

By default, the first parameter omits its external name, and the second and subsequent parameters use their local name as their external name.

If you follow this you can create methods without typing out the saperate external parameter names and yet your code follows the standard Swift naming conventions.

File: SwiftExamples/Rect.swift

import Foundation

class Rect: Shape {

    ...
    
    func increaseHeight(height: Int, width: Int) {
        self.height += height;
        self.width += width;
    }
}

File: SwiftExamples/main.swift

...

rect1.increaseHeight(30, width: 40)
rect1.describe()

output:

...
Rect - Height: 30 Width: 40

Initializers

Initializers look like methods but they have keyword init as their name. Initializers in Swift are similar to constructors in programming languages like Java and C#. They allow you to initialise the default state of the object.

Here is the rewritten Rect class which uses 2 initializers. The fitst one overrides the default no parameter initilizer whereas the other one accepts height and width parameters so that it is convenient to set when the object is being created.

File: SwiftExamples/Rect.swift

import Foundation

class Rect: Shape {
    
    var height: Int;
    var width: Int;
    
    override init() {
        height = 0
        width = 0
    }
    
    init(height h: Int, width w: Int) {
        height = h
        width = w
    }
    
    override func describe() {
        print("Rect - Height: \(height) Width: \(width)")
    }
    
    func area() -> Int {
        return width * height
    }
    
    func increaseHeight(height: Int, width: Int) {
        self.height += height;
        self.width += width;
    }
}

File: SwiftExamples/main.swift

...

var rect2 = Rect()
rect2.describe()

var rect3 = Rect(height:50, width:60)
rect3.describe()

output:

...
Rect - Height: 0 Width: 0
Rect - Height: 50 Width: 60

Class/Type Methods and Static/Type Properties

Type methods in Swift are similar to static methods in Java and C#. You can call these methods without creating an instance of the class.

Type properties are similar to static properties in Java and C#.

To define a type method, you use the class keyword, whereas to define a type property you use the static keyword.

In the following example, we use a type property instancesCreated to keep a count of total instances created using the Rect class. Also we have defined a type method printInstancesCreated which allows us to print the instancesCreated property.

One more thing to note that in type methods of the same class you can use the type properties with using class reference. But in the instance methods and initializers you need to use the class reference, for example, Rect.instancesCreated to use the type properties.

File: SwiftExamples/Rect.swift

import Foundation

class Rect: Shape {
    
    static var instancesCreated: Int = 0;
    
    class func printInstancesCreated() {
        print("Total instances created from Rect: \(instancesCreated)")
    }

    var height: Int;
    var width: Int;
    
    override init() {
        height = 0
        width = 0
        
        Rect.instancesCreated += 1
    }
    
    init(height h: Int, width w: Int) {
        height = h
        width = w
        
        Rect.instancesCreated += 1
    }
    
    override func describe() {
        print("Rect - Height: \(height) Width: \(width)")
    }
    
    func area() -> Int {
        return width * height
    }
    
    func increaseHeight(height: Int, width: Int) {
        self.height += height;
        self.width += width;
    }
}

File: SwiftExamples/main.swift

...
Rect.printInstancesCreated()

output:

...
Total instances created from Rect: 4

Now that we have looked at essentials of Object Oriented Programming in Swift, let's take a quick tour of some other essential features of the language.

Constants

The constants are declared with the keyword: let .

File: SwiftExamples/main.swift

...

let PI = 3.14
let BASE_URL: String = "http://mysite.com/api/"
print("PI:\(PI), BASE_URL: \(BASE_URL)")

output:

...
PI:3.14, BASE_URL: http://mysite.com/api/

Please note that as a best practice, you will notice that Swift progammmers are encouraged to use constants a lot more than variables.

If you need to initialize the value of a vairable only once in your function or a class, it is much better to use a contstant than a variable. This leads to more maintaible code as there is no chance of accidently modifying the value of a constant.

Optionals

Swift has a concept of optionals which is not present in C or Objective-C. If you have variable which might or might not have a value at a given time during the execution of a program, then you can declare it as optional by providing a ? after the typename.

To quote Apple's Swift Programming Language book:

An optional says:

There is a value, and it equals x

or

There isn’t a value at all

Swift's nil is also not same as nil in Objective-C. In Objective-C, nil can be set to only to variables of object type. In Swift, nil indicates absence of a value and can be set to variable of any type which is declared as optional.

File: SwiftExamples/main.swift

...

var num:Int? = 35
print("num: \(num)")
num = nil
print("num: \(num)")

output:

...
num: Optional(35)
num: nil

If Statements, Forced Unwrapping and Optional Chaining

If statements can be used to determine if an optional contains a value.

Note: Swift doesn't use round brackets in control flow statements, aroud the control conditions. This can be seen in the following if statement.

...

var rect4:Rect? = Rect(height:5, width:5)

if rect4 != nil {
    print("rect4.height: \(rect4!.height)")
} else {
    print("rect4 is nil")
}

output:

...
rect4.height: 5

Here in the if statement you have first made sure that rect4 is not null. Then to access the value, you need to use ! operator in the code that follows. So to access the height property, you need to write:

print("rect4.height: \(rect4!.height)")

The same line can also be written as:

print("rect4.height: \(rect4?.height)")

If you use ! operator (called as forced unwrapping) and the value of rect4 is nil, then there will be a runtime error. If you use ? operator (called as optional chaining) and the value of rect4 is nil, then the operation will fail gracefully.

However as a best practice, in case of optional variables, you should always make sure that optional variables are not nil using a if staetment and then only access the vlaue with forced unwrapping.

If you need to use the optional variable multiple times then you can use following tactic to convert the optional to a variable. Check how the instance variable window is converted into a constant in the if block. Once this is done, inside the if block you can use the window constant, without the ! operator.

class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?
    
    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        window = UIWindow(frame: UIScreen.mainScreen().bounds)
        if let window = window {
            window.backgroundColor = UIColor.whiteColor()
            window.makeKeyAndVisible()
        }
        return true
    }
    
    ...
    
}

As a best practice, while designing your own classes and APIs, try to use optionals as little as possible. Unfortunately, UIKit and other core iOS development frameworks are designed to use nil values at quite a few places. So you will see a lot of optionals being used in your code that depends on core iOS frameworks.

Protocols

Protocols in Swift have a lot of features compared to protocols in Objective-C. In Swift, the protocols can define propeties, static methods, regular methods, mutating methods, optional methods and required initilizers. To understand full capabilities of Protocols in Swift, please check the Protocols Section to the Swift Programming Language Book.

If you want to use optional methods in a protocol, then it must be marked with the @objc attribute. Then to use this protocol in a class, that class must be marked with the @objc attribute. Only classes that extend from NSObject can be marked with the @objc attribute.

File: SwiftExamples/Game.swift

import Foundation

@objc protocol GameDelegate {
    
    var moves : Int {get}
    
    func gameStarted()
    
    optional func gameMoved()
    
}

class Game {

    var delegate: GameDelegate?
    
    func startGame() {
        print("Game Started")
        delegate?.gameStarted()
    }
    
    func makeMove() {
        print("Made the move")
        delegate?.gameMoved?()
    }
    
}

@objc class GameDelegateImpl : NSObject, GameDelegate {
    
    var moves  = 0;
    
    func gameStarted() {
        print("GameDelegateImpl : gameStarted")
    }
}

File: SwiftExamples/main.swift

...

var game = Game()
game.delegate = GameDelegateImpl()
game.startGame()
game.makeMove()

output:

...
Game Started
GameDelegateImpl : gameStarted
Made the move

In this example, we have created a class Game . Also we have created the protocol GameDelegate . Since we want to provide an optional method in the protocol we need to mark it with @objc attribute.

In the Game class the delegate property is marked as optional. The programmer who is using the Game class will decide if he wants to provide a delegate or not. Hence in the implemetation of the Game class you need to use optional chaning delegate? while calling the methods on the delegate. This way if the delegate is nil , the operation will fail gracefully. Also since the method gameMoved is optional in the delegate, while calling the method on the delegate, you need to call the method via optional chaining ( delegate?.gameMoved?() ) so as to allow it to fail gracefully, if in case the delegate is provided, but the method is not implemented.

Finally, the class GameDelegateImpl implementes the GameDelegate protocol. Since the GameDelegate protocal has an optional method, the GameDelegateImpl needs to extend from NSObject and it needs to be marked with attribute @objc .

Conditionals

if...else Statement

In Swift, the brackets around the condition for the if statement (and in case of the loop statements too) are not required.

File: SwiftExamples/main.swift

...
    
var testNum = 13
    
if testNum % 2 == 1 {
    print("\(testNum) is an odd number.")
} else if testNum == 0 {
    print("testNum is zero.")
} else {
    print("\(testNum) is an even number but not zero.")
}

output:

...
13 is odd number.

Also you should note that the if statement in Swift expects the condition to evaluate to a boolean value. If you try to use Int as the type for the conditional the compiler will flag an error.

switch Statement

switch Statement in Swift is improved than that of C. Unlike C, in Swift in switch statement can use String values for comparison.

File: SwiftExamples/main.swift

...
    
var language = "English"

switch language {
    
case "English":
    print("You chose English language")
    
case "French":
    print("You chose French language")
    
default:
    print("You didn't choose a language")
}

output:

...
You chose English language

Also note the absence of the break statements in the above example. Unlike C, in Swift, the control doesn't fall through to the next case if the break statement is missing.

If you need to match one of the multiple options to the variable provided to the switch statement, then you can use comma separated values in the case statement.

File: SwiftExamples/main.swift

...

var cardType = "Master"
var interestRate: Float? = nil

switch cardType {

case "Visa", "Master":
    interestRate = 3.0

case "American Express":
    interestRate = 2.75

default:
    interestRate = 3.25
    
}
    
print("Interest Rate is \(interestRate)")

output:

...
Interest Rate is 3.0

Range Matching in switch Statement

You can also use ranges instead of constant values in the case statements.

File: SwiftExamples/main.swift

...

var dwarfs = 4

switch dwarfs {
    
case 0...6:
    print("Some dwarf brothers are missing!")
    
case 7:
    print("All dwarf brothers are present.")
    
default:
    print("You got it all wrong dude!")
    
}

output:

Some dwarf brothers are missing!

Control Flow Statements : for, while and do...while

In Swift, these loop constructs are similar that of C.

for Loop

Warning : In the 3.0 verion of the Swift programming language, the counter based C style for loop might be removed or deprecated . So do not use it for new code. Use the for...in loop instead.

File: SwiftExamples/main.swift

...
    
for var counter = 0; counter < 10; counter++ {
    print("counter: \(counter)")
}

output:

counter: 0
counter: 1
counter: 2
counter: 3
counter: 4
counter: 5
counter: 6
counter: 7
counter: 8
counter: 9

while Loop

File: SwiftExamples/main.swift

...
    
var index = 35.3

while index < 45.0 {
    
    print("index: \(index)")
    
    if index > 35.5 {
        break
    }
    
    index += 0.125
}

output:

...
index: 35.3
index: 35.425
index: 35.55

repeat...while Loop

File: SwiftExamples/main.swift

...

var card = 0

repeat {
    
    card++
    
    if card == 5 {
        continue
    }
    
    print("card: \(card)")
    
} while card < 10

output:

...
card: 1
card: 2
card: 3
card: 4
card: 6
card: 7
card: 8
card: 9
card: 10

Collection Types

Arrays

This is how you can declare arrays like this:

File: SwiftExamples/main.swift

...

var greatActors: [String] = ["Marlon Brando", "Jack Nicholson", "Morgan Freeman"]

var emptyArray = [Double]()

var arrayWithThreeValues = [Double](count: 3, repeatedValue: 0.0)

Here specifying the type is optional, if you are initializing the array with some values, as the compiler can detect the type for you.

File: SwiftExamples/main.swift

...

var greatDirectors = ["Steven Spielberg", "Francis Ford Coppola", "Quentin Tarantino"]

for...in Loop for Arrays

File: SwiftExamples/main.swift

...

print("Output all array elements:")

for director in greatDirectors {
    print("\(director)")
}

output:

...
Output all array elements:
Steven Spielberg
Francis Ford Coppola
Quentin Tarantino

Changing Array Elements

In Swift arrays (and other collections) are mutable if you use them as a variable. You can change, add and remove elements from an array as required if it is assigned to a variable. However, if you assign a collection to a constant then it is immutable, meaning its size and contents can't be changed.

It's a good practice to use collections as constants when you know beforehand that they are not going to change. The Swift compilar can add some optimizations based on this information.

Here are some examples of how you can manipulate arrays.

File: SwiftExamples/main.swift

...

greatDirectors[0] = "James Cameron"

You can also change the multiple array items with the range syntax:

File: SwiftExamples/main.swift

...

greatDirectors[1...2] = ["Robert Zemeckis", "Peter Jackson"]
    
print("Output all array elements:")

for director in greatDirectors {
    print("\(director)")
}

output:

...
Output all array elements:
James Cameron
Robert Zemeckis
Peter Jackson

Append Items to Array

File: SwiftExamples/main.swift

...

greatDirectors += ["Coen Brothers"]

greatDirectors += ["David Fincher", "Ang Lee"]

print("Output all array elements with indexs:")

for (i, director) in greatDirectors.enumerate() {
    print("\(i) : \(director)")
}

output:

...
Output all array elements with indexs:
0 : James Cameron
1 : Robert Zemeckis
2 : Peter Jackson
3 : Coen Brothers
4 : David Fincher
5 : Ang Lee

Note : Here the eumerate method of the array returns something called as "Tupal". Tupals are explained below.

Remove Items from Array

File: SwiftExamples/main.swift

...

greatDirectors.removeAtIndex(3)

print("Output all array elements with indexs:")

for (i, director) in greatDirectors.enumerate() {
    print("\(i) : \(director)")
}

output:

...
Output all array elements with indexs:
0 : James Cameron
1 : Robert Zemeckis
2 : Peter Jackson
3 : David Fincher
4 : Ang Lee

Array: Other Importnant Properties and Methods

File: SwiftExamples/main.swift

...
var directorsCount = greatDirectors.count
print("Number of Great Directors count: \(directorsCount)")

var arrayCapacity = greatDirectors.capacity
print("arrayCapacity: \(arrayCapacity)")

greatDirectors.removeAll(keepCapacity: false)
arrayCapacity = greatDirectors.capacity
print("arrayCapacity: \(arrayCapacity)")

greatDirectors.reserveCapacity(10)
arrayCapacity = greatDirectors.capacity
print("arrayCapacity: \(arrayCapacity)")

output:

...
Number of Great Directors count: 5
arrayCapacity: 6
arrayCapacity: 0
arrayCapacity: 10

Since arrays are mutable and indexed, sometimes it is useful to pay attention to the capacity of the array to ensure that you don't endup requesting too many memeory allocations which can hamper performance. For example, if you know beforehand that an array is going to require space for a hundred elements then you can reserve the capacity in advance.

Dictionaries

Dictionary is a key value data structure. Example:

File: SwiftExamples/main.swift

...

var movieActors: [String: String] = [
   "The Godfather": "Marlon Brando",
   "The Shawshank Redemption": "Morgan Freeman"
]

Like arrays if you are providing the initial values then you neednot specify the datatype as the compiler can detect it for you.

File: SwiftExamples/main.swift

var capitals = [
    "United States": "Washington, D.C.",
    "United Kingdom": "London"
]

Iterating over a Dictionary

File: SwiftExamples/main.swift

...

for(country, capital) in capitals {
    print("\(country) : \(capital)")
}

output:

...
United Kingdom : London
United States : Washington, D.C.

Dictionary: Accessing and Modifying Values

File: SwiftExamples/main.swift

...
movieActors["The Shawshank Redemption"] = "Tim Robbins"
movieActors["Green Lantern"] = "Ryan Reynolds"

print("Actor in Green Lantern: " + movieActors["Green Lantern"]!)

movieActors.removeValueForKey("Green Lantern")

print("movieActors count \(movieActors.count)")

for movie in movieActors.keys {
    print("\(movie) : \(movieActors[movie])")
}

output:

...
Actor in Green Lantern: Ryan Reynolds
movieActors count 2
The Godfather : Optional("Marlon Brando")
The Shawshank Redemption : Optional("Tim Robbins")

Tupals

Tupal is a concept found in many functional programming languages . Tupal is basically a sequence of data. It can contain items of different types. In Swift you can access tupal elements by indexes with "." syntax. You can also give names to the tupal elements and access the elements by names.

You can use tupals to return multiple values from fuctions.

File: SwiftExamples/main.swift

...

var aTupal = (2, "Mother", 3.5, "This example is pointless.")

print("second element of tupal : \(aTupal.1)")

var aCat = (name: "Kitty", kittens: 3)

print("Name of the cat: \(aCat.name)")

output:

second element of tupal : Mother
Name of the cat: Kitty

Characters and Strings

Characters and Strings datatyes in Swift support unicode from ground up.

Characters

File: SwiftExamples/main.swift

...

var aLetter: Character = "\u{03c0}"

print("aLetter: \(aLetter)")

output:

aLetter: π

Note: Here note that characters are defined using double quotes which is different from C and Objective-C. In Swift, since strings are also defined using double quotes to define a character variable you need to explictly specify the datatype.

Strings

File: SwiftExamples/main.swift

...

var aString: String = "this is a string"
print("aString : \(aString)")

aString += " with some words"
print("aString : \(aString)")

var anotherString = "This is another string"

for letter in anotherString.characters {
    print(letter)
}

print("the number of characters in '\(anotherString)' is \(anotherString.characters.count)")

output:

aString : this is a string
aString : this is a string with some words
T
h
i
s
 
i
s
 
a
n
o
t
h
e
r
 
s
t
r
i
n
g
the number of characters in 'This is another string' is 22

That's it! Here we have completed the tour of the essential syntax of the Swift programming language. Armed with this information, now you should be able to jump start an iOS application using the Swift programming language.

About the Author

I am Pritam Barhate. I am cofounder and CTO of Mobisoft Infotech, which is a iPhone & iPad Application Development Company. Mobisoft also has a lot of experience in creating scalable cloud based API backends for iOS and Android applications. For more information about various services provided by our company, please check our website.

Table of Contents