Welcome To Swift

Hey, thanks for checking out the microsite for my "Welcome to Swift" talk! I built this site to compliment my talk for Activate in Baton Rouge on November 3rd, 2016.

This talk provides a "swift" introduction to Apple's new programming language for iOS, watchOS, MacOS, and tvOS. We'll review some of Swift's primary language features before diving into Xcode to demo the language by building a bare bones iOS app. You'll walk away with some basic knowledge about the Swift ecosystem and insight into where to look to learn more.

You can download the slides for this talk here.

What is Swift?

Swift can be described many ways. Formally it is a "compiled, statically typed, object oriented language". More casually, it is a language developed by Apple for people building for their platforms, e.g. iOS, macOS, tvOS and watchOS.

Apple introduced us to Swift in June 2014. At that time they described it as "Objective-C" without the C. So what is Objective-C? Objective-C is an object oriented variant of C, and prior to 2014 it was the primary programming language for iOS and OS X.

So, when Apple said that Swift was "Objective-C without the C", they were saying it has all the power of Objective-C but with a more modern syntax and updated language features. At the time, this was evidenced by the tight relationship between the two languages. All of the old libs Apple had written for Objective-C were available to us in Swift, and, we could compile our old Objective-C code and our Swift code right alongside each other in the same app.

In December of 2015, Apple open sourced Swift. The code used to build the Swift compiler and its peripherals are available to the public. Apple also published Swift.org which serves as a roadmap for Swift's development and resources for developers and contributors.

Where do I get Swift

Mac Users

If you are a Mac user, Swift is comes built in. You can open a terminal and type swift and hit enter to start a Swift REPL. Here you can type Swift code and see the results of its execution.

To take full advantage of the language you'll want to install Xcode. Xcode is an IDE for Swift which contains all the tools you'll need to build applications. Xcode also offers interactive playgrounds which is a handly tool for prototyping and playing around with the Swift programming language.

iOS Users

iPad users can download the Swift Playgrounds iOS app. This app includes some interactive puzzles that are solved by writing Swift code.

Linux Users

Linux users can also use the Swift programming language. Swift.org has some information about installing Swift on a system running Linux.

Windows Users

¯\_(ツ)_/¯

Language Features

Let's review some of Swift's syntax and language features.

This review of language is by no means comprehensive. Check out Apple's documentation for a more thorough overview of the language.

Constants & Variables

In Swift, variables are declared with the var keywoard. A variable's value can be changed to a different value of the same type after it has been set.

var a = 5

Like a variable, a constant associates a name with a value. Unlike a variable, a constant's value cannont be changed after it has been set.

Constants are declared with the let keyword:

let b = 6

Type annotations can be used to describe a constant or variable's type explicitly. If no type annotation is provided, the constant or variable's type is infered from the value assigned.

let a: Int = 4
let c: String = "hello!"

Optionals

Swift has a concept of "optional types". This is similar to nil or null in other programming languages.

When a variable has an optional type that means that the variable can either have a value, or the absence of a value. In Swift the absence of a value is described as nil.

Optional types are described using a ?.

var optionalString: String? = "this could be nil. who knows? maybe?"
optionalString = nil  // no worries here

var nonoptionalString: String = "this cannot be nil"
nonoptionalString = nil  // this will explode

Before you can use the value in an optional, you must "unwrap" it. Optionals can be unwrapped with the !.

If you attempt to unwrap an optional that is nil, your program will crash and die.

var optionalInt: Int? = 5
optionalInt! + 5  // no worries. returns 10

optionalInt = nil
optionalInt! + 5  // this will explode.

Optionals can be "implicitly unwrapped" if you defined them with a ! instead of a ?. Implicitly unwrapped optionals do not need a ! to unwrap them.

Be careful because attempting to access an implicitly unwrapped optional that is nil will crash your program.

var unwrappedOptionalInt: Int! = 5
unwrappedOptionalInt + 5  // no worries. returns 10

unwrappedOptionalInt = nil
unwrappedOptionalInt + 5  // this will explode.

Comments

Swift uses the // syntax for single line comments and the /* */ sytax for mutliline comments.

// This is a single line comment
/* This is a multiline comment.
   It spans many lines */

You can use /** */ or /// for documentation comments.

If you document something in this way Xcode can help you refence that documentation later. For example, if you document a function, you can option + click the name of that function where it appears later in your code and see the documentation in a tooltip.

/**
 This function doubles an integer
*/
func double(value: Int) -> Int {
    return value * 2
}

/// This function halves an integer
func halve(value: Int) -> Int {
    return value / 2
}

Here's an example of what this looks like in Xcode:

Xcode documentation tooltip

Numbers

The most common numberic types in Swift are Int and Double. Additionally, you may see UInt which is an unsigned integer, Int64 and Int32 which are 64-bit and 32-bit integers respectively, and Float which is a floating point number.

let integer: Int = 5
let double: Double = 5.0

let unsignedInteger: UInt = 3

let int64Bit: Int64 = 6
let int32Bit: Int32 = 7

let float: Float = 2.7

Strings

Swift has a string type named String. Strings are declared using double quotes: ".

let helloWorld = "Hello, world!"

Strings are described as a collection of characters which conform to the Character type. A character can be defined using a type annotation with a single character string.

let characterH: Character = "H"

Operators

Swift uses = for the assignment operator. Swift also has compound assignment operators.

var a = 5  // a now equals 5

Swift has all of the basic arithmetic operators you would expect in a programming language:

1 + 2      // equals 3
3 - 4      // equals -1
5 * 6      // equals 30
7.0 / 8.0  // equals 0.875

These operators can be used on more than numeric values:

"hello, " + "world"  // equals "hello, world"

Swift also has all the basic comparison operators you'd expect in a programming language:

1 == 0   // false
2 != 1   // true
3 > 2    // true
4 < 3    // false
5 >= 4   // true
6 <= 5   // false

…and a standard set of built-in logical operators.

!true          // false
true || false  // true
true && false  // false

There's plenty of other fun operators that I don't have time to go into here, but here's a quick preview of some:

// The nil-coalescing operator
a ?? b
// The closed-range operator
1...5
// The half-open range operator
1..<5
// The ternary conditional operator
question ? "It's true!" : "It's false!"
// The remainder operator (different from a formal modulus operator, look it up!)
6 % 4
// The bitwise AND operator
0b11111100 & 0b00111111

To make things more exciting, Swift gives you the ability to overload operators and change their behavior. Additionally, you can define custom operators. Unfortunatly, I will not have the time to go too in depth with that here.

infix operator <!!>

extension Int {
  static func <!!>(a: Int, b: Int) -> Int {
    return (a + b) * 42
  }
}

4 <!!> 5  // equal 378, or (4 + 5) * 42

Collections

Swift's most common collection types are Array and Dictionary. Arrays represent ordered collections of objects and dictionaries represent key-value pairs.

Arrays

An array's type is described according to the type of elements it contains. For example, an array of integers would use the type [Int].

var arrayOfInts = [1, 2, 3]
var explicitArrayOfInts: [Int] = [4, 5, 6]
var emptyArrayOfInts = [Int]()

Arrays values can be accessed using indexes as subscripts.

arrayOfInts[1] // returns 2

Additionally, there's a rich set of methods that can be used to work with Arrays. Here's a few examples:

arrayOfInts.index(of: 3)   // returns 2
arrayOfInts.max()          // returns 3
arrayOfInts.min()          // returns 1
arrayOfInts.append(4)      // now equals [1, 2, 3, 4]
arrayOfInts.count          // returns 4
arrayOfInts.remove(at: 2)  // now equals [1, 2, 4]
arrayOfInts.first          // returns 1
arrayOfInts.last           // returns 4

Dictionaries

Dictionaries are also described according the the types of elements they contain. For example, a dictionary with keys of the type String and values of the type Int would use the type [String: Int]

var numbers = [
  "one": 1,
  "two": 2,
  "three": 3,
]
var emptyDictionary = [String: Float]()
var explicitDictionary: [Character: String] = [
  "a": "ay",
  "b": "bee",
  "c": "see"
]

Dictionary values can be accessed using the keys as subscripts.

numbers["one"] // returns 1

Like arrays, dictionaries provide a wide range of methods to those wishing to work with them. Here's a quick overview of a limitted set of those methods:

numbers.count                            // 3
numbers.isEmpty                          // false
numbers.removeValue(forKey: "two")       // key/value for "two" removed
numbers.updateValue(4, forKey: "three")  // numbers["three"] now equals 4
numbers.removeAll()                      // numbers is now empty

Control Flow

Swift has a wide array of built in statements to handle control flow. I'm only able to cover a few here. For a more comprehensive overview check out Apple's documentation.

If/Else

If statements work the same way they do in other programming language. Parentheses are optional.

var number = 5

if number == 5 {
  // do something
}

if number > 5 {
  // do something
} else {
  // do something else
}

if number > 5 {
  // do something
} else if number == 5 {
  // do something else
} else {
  // do something... elser...?
}

If statements can also be used with let to unwrap optionals.

This example if effectively saying: "If optionalNumber is not nil, assign it to the variable optionalNumber within the if statement's scope and print it out. If optionalNumber is nil, print out optionalNumber is nil."

var optionalNumber: Int? = 5

if let optionalNumber = optionalNumber {
  // optionalNumber is now available as an unwrapped optional
   print(optionalNumber)
} else {
  // optionalNumber is nil
  print("optionalNumber is nil")
}

Guard

Guard statements work similarly to if statements. They provide an else block which is executed if the conditional is false.

This is helpful for early exit from a function.

func fibonacci(at number: Int) -> Int {
  guard number > 1 else {
    return number
  }

  return fibonacci(at: number - 1) + fibonacci(at: number - 2)
}

fibonacci(at: 7)  // return 13

While Loops

Swift has while loops which execute a block until a given condition is false The example below will print 0, 1, 2, 3, and 4 in that order:

var counter = 0

while counter < 5 {
  print(counter)
  counter += 1
}

For Loops

Swift does not have traditional C-style for loops. Swift's does, however, have for-in loops which are designed to operate over a collection.

The following for loops have the same result as the while loop above:

for number in [0, 1, 2, 3, 4] {
  print(number)
}

for number in 0..<5 {
  print(number)
}

for character in "01234".characters {
  print(character)
}

Also available to collections is the forEach method:

[0, 1, 2, 3, 4].forEach { number in
  print(number)
}

(0..<5).forEach { number in
  print(number)
}

"01234".characters.forEach { character in
  print(character)
}

Switch Statements

Swift's switch statements take a value and compare it to a number of cases in a given order. It executes the code below the case that matches.

If no matching case is found, it executes the code below the default case.

Unlike a number of other popular languages, Swift's switch statements do not require an explicit break statement.

The example below will print three

var number = 3

switch number {
case 0:
    print("zero")
case 1:
    print("one")
case 2:
    print("two")
case 3:
    print("three")
default:
    print("Unrecognized number")
}

Functions

In Swift, functions use the func keyword. There's a whole array of modifiers that can be applied to functions but I'm not going to focus on those now.

Funtions can be used to perform simple tasks:

func sayHello() {
  print("Hello")
}
sayHello()  // prints "Hello"

Functions in can take arguments. Swift uses named arguments so the argument's name is used in the function call:

func sayHello(name: String) {
  print("Hello, " + name)
}
sayHello(name: "Chuck Norris")  // prints "Hello, Chuck Norris"

The argument's name in the invocation does not have to be name of the argument in the function definition.

func sayHello(to name: String) {
  print("Hello, " + name)
}
sayHello(to: "Bruce Lee")  // prints "Hello, Bruce Lee"

Functions can even opt out of using a name for an argument by using an _ as the name.

func sayHello(_ name: String) {
  print("Hello, " + name)
}
sayHello("Ip Man")  // prints "Hello, Ip Man"

Finally, functions can declare a return value using -> and the return value's type:

func helloString(for name: String) -> String {
  return "Hello, " + name
}
let string = helloString(for: "Kung Fury")
print(string)  // prints "Hello, Kung Fury"

Enums

Swift's Enums allow you to describe a group of related values and work with them in a safe way. Often times enums are used to describe a "type" of a thing.

Here is an example for types of primates:

enum PrimateType {
  case Monkey
  case Gorilla
  case Human
}

Enums are especially powerful when combined with switch statements. The example below prints *gorilla noise*:

var primateType = PrimateType.Gorilla

switch primateType {
case .Monkey:
    print("ooh ooh ahh ahh")
case .Gorilla:
    print("*gorilla noise*")
case .Human:
    print("Lorem Ipsum")
}

Classes & Structs

Swift provides classes and structs which can be used to structure data and organize functionality. Structs and classes are very similar. For example, both allow you to:

The difference is that classes provide some additional features including:

Structs are defined as follows:

struct Primate {
  let name: String
  let type: PrimateType

  func makeANoise() {
    switch type {
    case .Monkey:
      print("ooh ooh ahh ahh")
    case .Gorilla:
      print("*gorilla noise*")
    case .Human:
      print("Lorem Ipsum")
    }
  }
}

let harambe = Primate(name: "Harambe", type: .Gorilla)
print(harambe.name)   // prints Harambe
harambe.makeANoise()  // prints *gorilla noise*

Classes are defined as follows:

class Primate {
  let name: String
  let type: PrimateType

  init(name: String, type: PrimateType) {
    self.name = name
    self.type = type
  }

  func makeANoise() {
    switch type {
    case .Monkey:
      print("ooh ooh ahh ahh")
    case .Gorilla:
      print("*gorilla noise*")
    case .Human:
      print("Lorem Ipsum")
    }
  }
}

let batman = Primate(name: "Christian Bale", type: .Human)
print(batman.name)   // prints Christian Bale
batman.makeANoise()  // prints Lorem Ipsum

Note that the methods defined on a class or a struct use the self keyword to refer to the given instance of that class or struct. For example, to add a function that prints a Primate's first name:

struct Primate {
  // ...

  func firstName() -> String? {
    return self.name.components(separatedBy: " ").first
  }
}

let batman = Primate(name: "Christian Bale", type: .Human)

if let name = batman.firstName() {
  print(name)  // prints Christian
} else {
  print("Batman doesn't have a name")
}