Skip to main 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

Swift variables

Constants

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

Type inference

let school = "TalTech IT College"
let founded = 2000
let isAwesome = true

Variables

var age = 16

Strings

Concatenation

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

Interpolation

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

Full unicode support

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

Characters

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

Iteration

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

Collections

Array and Dictionary

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

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

Loops

While and Repeat-While

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
}
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

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

Half closed ranges

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

For-In Loop – Array & Dictionary

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

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

Array

Modifying

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

Append multiple

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

Remove elements (0 based index) and insert new ones

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

Optionals

Maybe value is not there?

let ages = ["Kalle": 17, "Malle": 18]
let possibleAge = ages["Malle"]
print("\(possibleAge)")

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

IOS

Checking

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

if let

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

switch

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

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

func sendMessage() {
    let message = "Hello!"
    print(message)
}

sendMessage()

Parameters

func sendMessage(shouting: Bool) {
    var message = "Hello!"
    message = shouting ? message.uppercased() : message
    print(message)
}

sendMessage(shouting: true)

Multiple parameters (argument, label)

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

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

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

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)
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

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

func sendMessage() {}  
() -> Void

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

Functions as parameters

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)

func divisibleByTwo(_ number: Int) -> Bool {
    return number % 2 == 0
}

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

Closures - definition

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

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

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)