Skip to content

11 - iOS Swift

Swift

  • Started in July 2010 – Chris Lattner
  • 1.0 Sept 9, 2014
  • 2.0 WWDC 2015
  • 2.2 Open Source (swift.org) Dec 3, 2015
  • 3.0 Sept 13, 2016
  • 4.0 Sept 19 2017, 4.1 March 2018, 4.2 Sept 2018
  • 5.0 March 3 2019

  • 2015 – Most loved programming language – first place (Stack Overflow)

  • 2016 – Second place
  • 2017-2018 In top 5

Swift Playgrounds

  • iPad app, 3D video game-like interface, moving closer to full editor
  • Xcode
  • Web based - http://online.swiftplayground.run

Swift variables

Constants

1
2
3
let school: String = "TalTech IT College"
let founded: Int = 2000
let isAwesome: Bool = true

Type inference

1
2
3
let school = "TalTech IT College"
let founded = 2000
let isAwesome = true

Variables

1
var age = 16

Strings

Concatenation

1
2
let school = "TalTech IT College"
let message = "Hello, " + school + "!" 

Interpolation

1
2
let school = "TalTech IT College"
let message = "Hello, \(school)!"

Full unicode support

1
let õäöüžšج信息技术 = "信息技术õäüöžšب ت جث"

Characters

1
2
3
let õäöüžšج信息技术 = "信息技术õäüöžšب ت جث"
print("\(õäöüžšج信息技术) is \(õäöüžšج信息技术.count) chars long")
\\ 16

Iteration

1
2
3
4
let õäöüžšج信息技术 = "信息技术õäüöžšب ت جث"
for character in õäöüžšج信息技术 {
    print(character)
}

Collections

Array and Dictionary

1
2
3
let names: [String] = ["Jüri", "Mari", "Kalle"]

let ages = ["Kalle": 17, "Malle": 18]

Loops

While and Repeat-While

1
2
3
4
5
6
var name = "test"
var i = 0
while i < name.characters.count {
    print("At pos \(i) is \(name[name.index(name.startIndex, offsetBy: i)])")
    i += 1
}
1
2
3
4
5
i = 0
repeat {
    print("At pos \(i) is \(name[name.index(name.startIndex, offsetBy: i)])")
    i += 1
} while i < name.characters.count

For-In Loop – closed ranges

1
2
3
for number in 1...5 {
    print(number)
}

Half closed ranges

1
2
3
4
5
let numbers = [7, 6, 42, 3, 9, 1]
let maxCount = 4
for index in 0..<maxCount {
    print(numbers[index])
}

For-In Loop – Array & Dictionary

1
2
3
4
5
let ages = ["Kalle": 17, "Malle": 18]

for (name, age) in ages {
    print("\(name) - \(age)")
}

Array

Modifying

1
2
3
var numbers = [7, 6, 42, 3, 9, 1]
numbers.append(5)
numbers[1] = 8

Append multiple

1
numbers.append(contentsOf: [4, 13, -5])

Remove elements (0 based index) and insert new ones

1
numbers[3...5] = [1, 2]

Optionals

Maybe value is not there?

1
2
3
4
5
let ages = ["Kalle": 17, "Malle": 18]
let possibleAge = ages["Malle"]
print("\(possibleAge)")

let possibleAge: Int? = ages["Malle"]

IOS

Checking

1
2
3
if possibleAge == nil {
    print("Age not found.")
}

if let

1
2
3
4
let ages = ["Kalle": 17, "Malle": 18]
if let age = ages["Kalle"] {
    print("Kalle's age is \(age)")
}

switch

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
let age = 90
switch age {
case 1:
    print("First year done")
case 13...19:
    print("Teenager is hard period!")
case let decade where decade % 10 == 0:
    print("Congrats on \(decade)*10 years")
default:
    print("regular birthday")

Switch over multiple values

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
let userName = "admin"
let passwordIsValid = true

switch (userName, passwordIsValid) {
case ("admin", true):
    print("admin you are")
case ("guest", _):
    print("guests not allowed")
case (_, let isValid):
    print(isValid ? "admin area granted" : "DENIED")
}

Functions

1
2
3
4
5
6
func sendMessage() {
    let message = "Hello!"
    print(message)
}

sendMessage()

Parameters

1
2
3
4
5
6
7
func sendMessage(shouting: Bool) {
    var message = "Hello!"
    message = shouting ? message.uppercased() : message
    print(message)
}

sendMessage(shouting: true)

Multiple parameters (argument, label)

1
2
3
4
5
func sendMessage(recipient: String, shouting: Bool) {
    let message = "Hello \(recipient)!"
    print(shouting ? message.uppercased() : message)
}
sendMessage(recipient: "Andres", shouting: true)

Better to read in usage, bad in function code

1
2
3
4
5
func sendMessage(to: String, shouting: Bool) {
    let message = "Hello \(to)!"
    print(shouting ? message.uppercased() : message)
}
sendMessage(to: "Andres", shouting: true)

Parameters - argument label and a parameter name

1
2
3
4
5
6
func sendMessage(to recipient: String, shouting: Bool) {
    let message = "Tere \(recipient)!"
    print(shouting ? message.uppercased() : message)
}

sendMessage(to: "Andres", shouting: true)

Parameters – using underscore – no label

1
2
3
4
5
6
func sendMessage(message: String, to recipient: String, shouting: Bool) {
    let message = "\(message), \(recipient)!"
    print(shouting ? message.uppercased() : message)
}

sendMessage(message: "Hello", to: "Andres", shouting: true)
1
2
3
4
5
6
func sendMessage(_ message: String, to recipient: String, shouting: Bool) {
    let message = "\(message), \(recipient)!"
    print(shouting ? message.uppercased() : message)
}

sendMessage("Hello", to: "Andres", shouting: true)

Return values

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
func firstString(havingPrefix prefix: String, in strings: [String]) -> String? {
    for string in strings {
        if string.hasPrefix(prefix){
            return string
        }
    }
    return nil
}

print("Result \(firstString(havingPrefix: "And", in: ["Jüri", "Andres"]))")

Function type

Function type
(parameter types) -> return type

1
2
3
4
5
func sendMessage() {}  
() -> Void  

func firstStr(havingPrefix prefix: String, in strings: [String]) -> String? {}  
(String, [String]) -> String?  

Functions as parameters

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
func filterInts(_ numbers: [Int], _ includeNumber: (Int) -> Bool) -> [Int] {
    var result: [Int] = []
    for number in numbers {
        if includeNumber(number) {
            result.append(number)
        }
    }
    return result
}

let numbers = [4, 17, 34, 41]
func divisibleByTwo(_ number: Int) -> Bool {
    return number % 2 == 0
}

let evenNumbers = filterInts(numbers, divisibleByTwo)
print(evenNumbers)

Closure expression - Inline function definitions (not named functions)

1
2
3
4
5
6
func divisibleByTwo(_ number: Int) -> Bool {
    return number % 2 == 0
}

let evenNumbers = 
    filterInts(numbers, { (number: Int) -> Bool in return number % 2 == 0})

Closures - definition

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
func filterInts(_ numbers: [Int], _ includeNumber: (Int) -> Bool) -> [Int] {……}

let numbers = [4, 17, 34, 41]
print( filterInts(numbers, { (number: Int) -> Bool in return number % 2 == 0}) )

// can be inferred from filterIntents declaration
print( filterInts(numbers, { number in return number % 2 == 0}) )

// if its single liner, no need for return keyword
print( filterInts(numbers, { number in number % 2 == 0}) )

// implicit arguments, no need for in keyword
print( filterInts(numbers, {$0 % 2 == 0}) )

// if closure is last argument, you can write as trailing closure
print( filterInts(numbers) {$0 % 2 == 0} )

Generics

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
let numbers = [4, 17, 34, 41]
let names = ["Andres", "kala"]

func filter<TElement>(_ source: [TElement],
                         _ includeElement: (TElement) -> Bool) -> [TElement] {
    var result: [TElement] = []
    for elem in source {
        if includeElement(elem) {
            result.append(elem)
        }
     }
    return result
}

let evenNumbers = filter(numbers) { $0 % 2 == 0 }
let shortNames = filter(names) { name in name.count < 5 }

Map, Filter

Closures and generics are widely used in Swift libraries

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
let names = ["Lily", "Santiago", "Aadya", "Jack", "Anna", "Andrés"]

let shortNames = names.filter({ name in name.count < 5 })

let shortNames1 = names.filter() { name in name.count < 5 }

let shortNames2 = names.filter { name in name.count < 5 }

print(shortNames)

let capitalizedShortNames = shortNames.map { name in name.uppercased() }
print(capitalizedShortNames)