Slide 1

Slide 1 text

Quick Intro to Swift - language Jussi Pohjolainen

Slide 2

Slide 2 text

Swift • Swift is a general purpose, multi-paradigm, compiled programming language • Developed by Apple • iOS, iPadOS, macOS, watchOS, tvOS • Also available for Linux and Windows • Replacement for Obj-C • Swift is open source • https://swift.org/ • Just download Xcode on Mac and you are ready to go

Slide 3

Slide 3 text

Hello World in Obj-C $ ls helloworld.m $ cat helloworld.m // First program example #import int main (int argc, const char * argv[]) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSLog (@"Hello, World!"); [pool drain]; return 0; } $ clang -framework foundation helloworld.m $ ls a.out helloworld.m $ ./a.out 2015-03-05 09:26:00.678 a.out[40432:5270985] Hello, World!

Slide 4

Slide 4 text

Hello World in Swift! That was Easy! > ls helloworld.swift > cat helloworld.swift print("Hello, world!") > swift helloworld.swift Hello, world!

Slide 5

Slide 5 text

Compiling in Swift > ls helloworld.swift > cat helloworld.swift print("Hello, world!") > swiftc helloworld.swift > ./hello Hello, world!

Slide 6

Slide 6 text

Swift Types

Slide 7

Slide 7 text

Types • Named type • Type that has a name • Classes, structures, enumerations, protocols, arrays, dictionaries • "Primitive types" are also named types (numbers, characters, strings) • You can extend the behaviour of these using extensions • Compound types • Type without a name • Function types and tuple types • Function type example: • ((Int, Int)) -> Void • All types are "non primitive"

Slide 8

Slide 8 text

Named Basic Types Types with name

Slide 9

Slide 9 text

Named Types • Swift has it's own versions of C / Obj-C types: • Int, Double, Float, Bool, String .. • Also collection types: • Array and Dictionary • Also a concept called optional types • Swift is a type – safe language, you cannot pass a String to an int

Slide 10

Slide 10 text

Float Documentation It's a struct!

Slide 11

Slide 11 text

And it has methods

Slide 12

Slide 12 text

Example let x : Float = 1.12 let y = x.rounded() print(y)

Slide 13

Slide 13 text

Constants (let) and Variables (var) • To declare a a constant, use keyword let let myConstant = 10 • To declare a variable, use keyword var var myVariable = 20 • You can do this in on line var x = 0, y = 0, z = 0 • Use Type Annotation to declare a type var hello: String • It's rare you need to use type annotation; variable type is given in initial value. • You can use unicode! let π = 3.14159 let = "" let = "dogcow"

Slide 14

Slide 14 text

Comparison between common languages Swift Java Kotlin ECMAScript Variable var x = 5 int x = 5 var x = 5 let x = 5 Constant variable let PI = 3.14 final double PI = 3.14 val PI = 3.14 const PI = 3.14

Slide 15

Slide 15 text

Comments • Comments very similar than in C • One line // one line • Multiline /* multiline multiline */ • Can be also nested (unlike in C) /* You can use /* nested comments */ like this */

Slide 16

Slide 16 text

Numbers and Boolean Integers Types (these are also structs) • Int8, Int16, Int32, Int64 • UInt8, UInt16, UInt32, UInt64 Integer Bounds let minValue = UInt8.min // 0 let maxValue = UInt8.max // 255 You can also just use Int • On 32-bit platform, Int -> Int32 • On 64-bit platform, Int -> Int64 Floating Point Numbers Types • Double for 64-bit • Float for 32-bit Boolean • Bool is either true or false

Slide 17

Slide 17 text

Type Safety • Swift is very clear about types, If it's String you cannot pass a Int • You don't have to declare type, but it has a type! let a = 5 // It's an Int! let π = 3.14 // It's a Double! • You can cast Integers let one: UInt8 = 1 let bigger : UInt16 = UInt16(one) • And floating – points let pi = Double(three)

Slide 18

Slide 18 text

Compound Type: tuple

Slide 19

Slide 19 text

Tuples • Tuples group multiple values into a single compound value let contact : (String, Int) = ("Jack", 123456) print(type(of: contact)) • You can decompose let (name, number) = contact • If you want the other, use underscore let (name, _) = contact • Indexes also available var name = contact.0 • Naming let contact : (name: String, number: Int) = (name: "Jack", number: 123456) print(contact.name) • Useful in functions that returns multiple values

Slide 20

Slide 20 text

Optionals

Slide 21

Slide 21 text

Optionals: ? • Add ? to the end of the type to declare a optional chaining • This means that the variable may hold also value nil: // x may be integer OR nil var x : Int? • If you make calculations, this fails because x may hold nil! var sum = x + 5 • You can unwrap the ? from the variable using ! var sum = x! + 5 • Now it crashes runtime if x holds nil, but it compiles

Slide 22

Slide 22 text

class StockExchange { public static String findStockCode(String company) { if(company.equals("Nokia")) { return "NOK"; } else if (company.equals("Apple")) { return "AAPL"; } else { return null; } } } class MyApp { public static void main(String [] args) { String code = StockExchange.findStockCode( args[0] ); System.out.println( code.toLowerCase() ); } } What is a possible error here? Running Java app: java MyApp Microsoft

Slide 23

Slide 23 text

class StockExchange { class func findStockCode(company : String) -> String? { if(company == "Nokia") { return "NOK" } else if (company == "Apple") { return "AAPL" } else { return nil } } } var code : String? = StockExchange.findStockCode( company: CommandLine.arguments[1] ); print(code.lowercased()) error: value of optional type 'String?' must be unwrapped to refer to member 'lowercased' of wrapped base type 'String' print(code.lowercased())

Slide 24

Slide 24 text

Checking and Unwrapping class StockExchange { class func findStockCode(company : String) -> String? { if(company == "Nokia") { return "NOK"; } else if (company == "Apple") { return "AAPL"; } else { return nil; } } } var code : String? = StockExchange.findStockCode( company: CommandLine.arguments[1] ); if code != nil { print(code!.lowercased()); } Checking for null values. Also ! is mandatory here.

Slide 25

Slide 25 text

Conditional unwrapping class StockExchange { class func findStockCode(company : String) -> String? { if(company == "Nokia") { return "NOK"; } else if (company == "Apple") { return "AAPL"; } else { return nil; } } } var code : String? = StockExchange.findStockCode( company: CommandLine.arguments[1] ); if let checkedCode = code { print(checkedCode.lowercased()); } It will unwrap the conditional of the code variable

Slide 26

Slide 26 text

Example let optionalValue1 : Int? = Bool.random() ? 5 : nil let optionalValue2 : Int? = Bool.random() ? 5 : nil if let value1 = optionalValue1 { if let value2 = optionalValue2 { print("\(value1 + value2)") } }

Slide 27

Slide 27 text

With one line let optionalValue1 : Int? = Bool.random() ? 5 : nil let optionalValue2 : Int? = Bool.random() ? 5 : nil if let value1 = optionalValue1, let value2 = optionalValue2 { print("\(value1 + value2)") }

Slide 28

Slide 28 text

class Stock { var code: String? var price: Double? } class StockExchange { class func findStockCode(company : String) -> Stock? { if(company == "Nokia") { let nok = Stock() nok.code = "NOK" nok.price = 6.5 return nok; } else if (company == "Apple") { let aapl = Stock() aapl.code = "AAPL" return aapl; } else { return nil; } } } if let stock = StockExchange.findStockCode( company: CommandLine.arguments[1] ) { if let price = stock.price { print(price) } } We will have multiple conditional unwrapping here... We will have multiple conditional unwrapping here...

Slide 29

Slide 29 text

class Stock { var code: String? var price: Double? } class StockExchange { class func findStockCode(company : String) -> Stock? { if(company == "Nokia") { let nok = Stock() nok.code = "NOK" nok.price = 6.5 return nok; } else if (company == "Apple") { let aapl = Stock() aapl.code = "AAPL" return aapl; } else { return nil; } } } if let stock = StockExchange.findStockCode( company: CommandLine.arguments[1] ) { if let price = stock.price { print(price) } } We will have multiple conditional unwrapping here... We will have multiple conditional unwrapping here...

Slide 30

Slide 30 text

class Stock { var code: String? var price: Double? } class StockExchange { class func findStockCode(company : String) -> Stock? { if(company == "Nokia") { let nok = Stock() nok.code = "NOK" nok.price = 6.5 return nok; } else if (company == "Apple") { let aapl = Stock() aapl.code = "AAPL" return aapl; } else { return nil; } } } if let stock = StockExchange.findStockCode( company: CommandLine.arguments[1] ), let price = stock.price { print(price) } With one line

Slide 31

Slide 31 text

class Stock { var code: String? var price: Double? } class StockExchange { class func findStockCode(company : String) -> Stock? { if(company == "Nokia") { let nok = Stock() nok.code = "NOK" nok.price = 6.5 return nok; } else if (company == "Apple") { let aapl = Stock() aapl.code = "AAPL" return aapl; } else { return nil; } } } if let price = StockExchange.findStockCode( company: CommandLine.arguments[1] )?.price { print(price) } Or...

Slide 32

Slide 32 text

Example class Person { var pet : Pet? = Bool.random() ? Pet() : nil } class Pet { var favoriteToy : String? = Bool.random() ? "Ball" : nil } let tina : Person? = Bool.random() ? Person() : nil if let t = tina, let p = t.pet, let f = p.favoriteToy { print(f) }

Slide 33

Slide 33 text

... or class Person { var pet : Pet? = Bool.random() ? Pet() : nil } class Pet { var favoriteToy : String? = Bool.random() ? "Ball" : nil } let tina : Person? = Bool.random() ? Person() : nil if let f = tina?.pet?.favoriteToy { print(f) }

Slide 34

Slide 34 text

Using ! or ? let toy1 : String? = tina?.pet?.favoriteToy let toy2 : String = tina!.pet!.favoriteToy!

Slide 35

Slide 35 text

Downcasting using as! or as? • To downcast an object to subtype, use • as? = If downcast was unsuccessful, put nil to the type • as! = If downcast was unsuccessful, crash • as? - example • var number1 = dict[2] as? Int • println(number1) // optional(7) • as! - example • var number2 = dict[2] as! Int • println(number2) // 7

Slide 36

Slide 36 text

Optionals: ! • In addition to creating optional with ? you can use ! • By using ? this will NOT work • let y : Int? = 12 • print(y + y) • Either check if not null OR use ! (=will crash if nil) • let y : Int? = 12 • print(y! + y!) • If you have to mark ! in everywhere, shortcut • let y : Int! = 12 • print(y + y) • The y is now optional, but you do not have to unwrap it everytime

Slide 37

Slide 37 text

Example let x : Int? = Bool.random() ? 5 : nil print(x! + x!) let x : Int! = Bool.random() ? 5 : nil print(x + x) Crash if nil values Crash if nil values

Slide 38

Slide 38 text

Lab

Slide 39

Slide 39 text

Some Control Structures

Slide 40

Slide 40 text

if var grade = 0 if grade == 0 { print("fail") } No need for (...)

Slide 41

Slide 41 text

while var i = 0 while i < 10 { print("\(i)") i += 1 }

Slide 42

Slide 42 text

repeat while var i = 0 repeat { print("\(i)") i += 1 } while i < 10

Slide 43

Slide 43 text

What...?

Slide 44

Slide 44 text

for - loop for index in 1...5 { print("\(index)") } for index in 1..<5 { print("\(index)") } for _ in 1...5 { print("hello") }

Slide 45

Slide 45 text

for - loop // 0, 2, 4, 6, 8 for index in stride(from: 0, to: 10, by: 2) { print("\(index)") } // 0, 2, 4, 6, 8, 10 for index in stride(from: 0, through: 10, by: 2) { print("\(index)") }

Slide 46

Slide 46 text

Functions

Slide 47

Slide 47 text

Defining a Function • Simple example about function func sayHello(personName: String) -> String { let greeting = "Hello, " + personName + "!" return greeting } • Return type is indicated using the return arrow -> • Using parameters is easy func sum(start: Int, end: Int) -> Int { return start + end } • You can return several values using Tuples func doSomething(start: Int, end: Int) -> (start: Int, end: Int) { return (start, end) }

Slide 48

Slide 48 text

Calling a Function • Does not work! func sum(start: Int, end: Int) -> Int { return start + end } print( sum(5,5) ) • Change... print( sum(start: 5, end:5) )

Slide 49

Slide 49 text

Function Parameter Names • Problem: What is the purpose of the given parameters? join("Hello", "World", ","); • Solution join(string: "Hello", and: "World", withJoiner: ",") • How? func join(string: String, and string2: String, withJoiner joiner: String) { ... }

Slide 50

Slide 50 text

Omitting External Name • It's possible to omit external name using _ func join(_ string: String, and string2: String, withJoiner joiner: String) -> String { return string1 + joiner + string2; } print( join("two", and: "three", withJoiner: "+") );

Slide 51

Slide 51 text

Default Parameter Names • Func definition func findInArray(myArray: [Int], value value: Int = 0) -> Int { .. } • Function calling findInArray(myArray: array, value: 2); findInArray(myArray: array);

Slide 52

Slide 52 text

Variadic Parameters • A variadic parameter accepts zero or more values of a specified type • Use ... after parameters name func giveNumbers(numbers: Int...) { } • And now you can use the function giveNumbers(numbers: 4,3,2) giveNumbers(numbers: 4)

Slide 53

Slide 53 text

inout parameters • Objects/functions are reference types, others value types • To pass a reference of an variable, use inout func passNumber(number: inout Int) { number = 1; } • And usage var number = 4 passNumber(number: &number) print("\(number)")

Slide 54

Slide 54 text

Function Types • Functions are variables. Declare a variable with function type! var mathFunction: (Int, Int) -> Int • Define two different functions func sum(a: Int, b: Int) -> Int { return a + b; } func extract(a: Int, b: Int) -> Int { return a - b; } • And usage var myVar: (Int, Int) -> Int myVar = sum myVar = extract • Function can be a parameter and return type!

Slide 55

Slide 55 text

Closures • Closures are like lambdas in Java / C# or blocks in Obj-C • Like mini-functions without a name • Syntax { (parameters) -> returntype in statements }

Slide 56

Slide 56 text

Passing Function to a function func fun(msg: String) { print(msg) } func isPositiveInteger(number : Int, success: (String) -> Void) { if(number > 0) { success("it was positive") } } isPositiveInteger(number: 5, success: fun)

Slide 57

Slide 57 text

Closure Expression Syntax func isPositiveInteger(number : Int, success: (String) -> Void) { if(number > 0) { success("it was positive") } } isPositiveInteger(number: 5, success: {(msg: String) -> Void in print(msg) }) Passing closure

Slide 58

Slide 58 text

Closure Expression Syntax func isPositiveInteger(number : Int, success: (String) -> Void) { if(number > 0) { success("it was positive") } } isPositiveInteger(number: 5, success: {msg -> Void in print(msg) }) Omit type

Slide 59

Slide 59 text

Closure Expression Syntax func isPositiveInteger(number : Int, success: (String) -> Void) { if(number > 0) { success("it was positive") } } isPositiveInteger(number: 5, success: {msg in print(msg) }) Omit return type

Slide 60

Slide 60 text

Shorthand Argument name func isPositiveInteger(number : Int, success: (String) -> Void) { if(number > 0) { success("it was positive") } } isPositiveInteger(number: 5, success: { print($0) } ) Output the first argument

Slide 61

Slide 61 text

Trailing Closure func isPositiveInteger(number : Int, success: (String) -> Void) { if(number > 0) { success("it was positive") } } isPositiveInteger(number: 5) { print($0) } If final argument is function, you can use also trailing syntax

Slide 62

Slide 62 text

Trailing Closure func isPositiveInteger(number : Int = 5, success: (String) -> Void) { if(number > 0) { success("it was positive") } } isPositiveInteger() { print($0) } Default value usage

Slide 63

Slide 63 text

Trailing Closure func isPositiveInteger(number : Int = 5, success: (String) -> Void) { if(number > 0) { success("it was positive") } } isPositiveInteger { print($0) } With no arguments we can omit ()

Slide 64

Slide 64 text

SwiftUI Example HStack { Text("Target Color Block") Text("Target Color Block") } Trailing Closure Usage here...

Slide 65

Slide 65 text

Array Examples

Slide 66

Slide 66 text

Usage: external Function func modify(item: String) -> String { return "
  • " + item + "
  • " } var shoppingList: [String] = ["Eggs", "Milk"] var htmlUI : [String] = shoppingList.map(modify) print(htmlUI)

    Slide 67

    Slide 67 text

    Usage: Closure var shoppingList: [String] = ["Eggs", "Milk"] var htmlUI : [String] = shoppingList.map({item -> String in return "
  • " + item + "
  • " }) print(htmlUI)

    Slide 68

    Slide 68 text

    Usage: Closure var shoppingList: [String] = ["Eggs", "Milk"] var htmlUI : [String] = shoppingList.map({ return "
  • " + $0 + "
  • " }) print(htmlUI)

    Slide 69

    Slide 69 text

    Usage: Closure, trailing var shoppingList: [String] = ["Eggs", "Milk"] var htmlUI : [String] = shoppingList.map() { return "
  • " + $0 + "
  • " } print(htmlUI)

    Slide 70

    Slide 70 text

    Usage: Closure, automatic return var shoppingList: [String] = ["Eggs", "Milk"] var htmlUI : [String] = shoppingList.map() { "
  • " + $0 + "
  • " } print(htmlUI)

    Slide 71

    Slide 71 text

    String interpolation var shoppingList: [String] = ["Eggs", "Milk"] var htmlUI : [String] = shoppingList.map() { "
  • \($0)
  • " } var htmlUIString : String = htmlUI.joined(separator: "") print("""
      \(htmlUIString)
    """)

    Slide 72

    Slide 72 text

    Strings and Arrays

    Slide 73

    Slide 73 text

    String Creation var stringA = "Hello" print( stringA ) var stringB = String("Hello") print( stringB ) let stringC = """ Hello Hello """ print(stringC)

    Slide 74

    Slide 74 text

    String Interpolation let a = 2 var c = 2.2 var stringA = "it's easy to embed variables like a = \(a) and c = \(c)" print( stringA )

    Slide 75

    Slide 75 text

    Iteration and equal var varA = "Hello, World!" var varB = "Hello, World!" if varA == varB { print("equal") } print(varA.count) for char in varA { print(char) }

    Slide 76

    Slide 76 text

    Collection Types: Array • Array var shoppingList: [String] = ["Eggs", "Milk"] var shoppingList = ["eggs", "Milk"] var someInts = [Int]() • Length of an Array shoppingList.count • Appending shoppingList.append("bread") shoppingList += ["Tomato"] • Retrieve shoppingList[0] • Change range shoppingList[0...3] = ["bananas", "apples", "coffee"] • Insert shoppingList.insert("something", atIndex:0)

    Slide 77

    Slide 77 text

    Iterating Array • for-in loop for item in shoppingList { println(item) } for item in 1...5 { println(item) } for _ in 1...5 { } • Enumerate for(index, value) in enumerate(shoppingList) { println(index) println(value) }

    Slide 78

    Slide 78 text

    Collection Types: Dictionary • Dict: key – value pairs • Key is unique, no spesified order • Usage var dictionary : [String: String] = ["key1": "value1", "key2": "value2"] var dictionary = [String: String]() • Append dictionary["key3"] = "value3" • Remove dictionary.removeValueForKey("key3") • Iterating for(key, value) in dictionary { ... } • Access keys or values dictionary.keys dictionary.values Unlike tuple, this must have keys and items can be added and removed dynamically

    Slide 79

    Slide 79 text

    Ranges let range: ClosedRange = 0...10 print(range.first!) // 0 print(range.last!) // 10 for index in range { print(index) } let names = ["Jack", "Tina", "Paul"] print(names[0...1]) let range2: Range = 0..<10 print(range2.first!) // 0 print(range2.last!) // 9 print(names[0..<2]) Type is ClosedRange Type is Range

    Slide 80

    Slide 80 text

    OO with Swift

    Slide 81

    Slide 81 text

    Classes vs Structures • Structures • Properties (Attributes) and functions (methods) • Initializers (Constructors) • Can conform to a protocol (Interface) • Can be extended using extension • Value type • Class can have additional capabilities • Can be inherited • Deinitializers available • Can be referenced more than one time • Reference type

    Slide 82

    Slide 82 text

    Moving from Classes to Structs • SwiftUI heavily uses Structs over Classes • Classes become bloated because of inheritance (look at UIView) • You can extend structs with extension • Struct instances are allocated on stack, drastically faster • In multithreaded environment structs are safer (value type) • When making changes to a struct it does not influence any other part of the app (value type)

    Slide 83

    Slide 83 text

    Struct struct Person { var name: String = "" var age: Int = 0 } var jack = Person() jack.name = "Jack" jack.age = 30 print("\(jack.name)")

    Slide 84

    Slide 84 text

    Comparing Structs struct Person { var name: String = "" var age: Int = 0 } var a = Person() a.name = "Jack" a.age = 30 var b = Person() b.name = "Jack" b.age = 30 print(a == b) helloworld.swift:14:9: error: binary operator '==' cannot be applied to two 'Person' operands print(a == b)

    Slide 85

    Slide 85 text

    Comparing Structs: global function == func == (left: Person, right: Person) -> Bool { return (left.name == right.name) && (left.age == right.age) } struct Person { var name: String = "" var age: Int = 0 } var a = Person() a.name = "Jack" a.age = 30 var b = Person() b.name = "Jack" b.age = 30 print(a == b) Comparison now works

    Slide 86

    Slide 86 text

    Equatable protocol struct Person: Equatable { var name: String = "" var age: Int = 0 } var a = Person() a.name = "Jack" a.age = 30 var b = Person() b.name = "Jack" b.age = 30 print(a == b) Equatable protocol provides default == function to the struct

    Slide 87

    Slide 87 text

    Equatable protocol struct Person: Equatable { var name: String = "" var age: Int = 0 static func == (left: Person, right: Person) -> Bool { return (left.name == right.name) } } var a = Person() a.name = "Jack" a.age = 40 var b = Person() b.name = "Jack" b.age = 30 print(a == b) Possible to override the default implementation

    Slide 88

    Slide 88 text

    Using Class class Person: Equatable { var name: String = "" var age: Int = 0 static func == (left: Person, right: Person) -> Bool { return (left.name == right.name) } } var a = Person() a.name = "Jack" a.age = 40 var b = Person() b.name = "Jack" b.age = 40 print(a === b) print(a == b) ?

    Slide 89

    Slide 89 text

    Properties • Properties are variables or constants in classes, structs or enumerations. • Stored properties • let property: (Int) • var property: (Int) • Computated properties • calculate the value of property using get and set • Property observers • Monitor changes in property's value • Every property needs to be assigned a value either during declaration or in the initializer

    Slide 90

    Slide 90 text

    Stored Properties struct Point { var x : Int var y : Int init(x: Int, y: Int) { self.x = x self.y = y } } var a = Point(x:0, y:0) a.x = 9 print(a)

    Slide 91

    Slide 91 text

    Computated Properties • Computated properties does not store a value! • Provide getter and setter (optional) that calculates some value • The property value is meant to be computed from other instance properties! Computated property is not in memory

    Slide 92

    Slide 92 text

    class Time { var seconds: Double = 0 init(seconds: Double) { self.seconds = seconds } var minutes: Double { get { return (seconds / 60) } set { self.seconds = (newValue * 60) } } } var t = Time(seconds: 60) print(t.seconds) t.minutes = 90 print(t.seconds) print(t.minutes)

    Slide 93

    Slide 93 text

    struct Person { private var _age : Int = 0 init(age: Int) { self.age = age } var age: Int { set { if(newValue > 0) { self._age = newValue } } get { return self._age } } } var t = Person(age: 20) t.age = -80 print(t.age) // 20 This will invoke setter

    Slide 94

    Slide 94 text

    Static struct Circle { static var PI : Double = 3.14 static func calculateArea(radius: Double) -> Double { return Circle.PI * radius * radius; } } print(Circle.calculateArea(radius: 5)) // Won't work // var c = Circle() // print(c.calculateArea(radius: 5))

    Slide 95

    Slide 95 text

    Class Inheritance, overriding: static class BaseClass { static func someStaticMethod() -> Void { print("someStaticMethod") } } class ChildClass : BaseClass { override static func someStaticMethod() -> Void { print("overriden method") } } // error: cannot override static method ChildClass.someStaticMethod()

    Slide 96

    Slide 96 text

    Class Inheritance, overriding: class class BaseClass { class func someStaticMethod() -> Void { print("someStaticMethod") } } class ChildClass : BaseClass { override static func someStaticMethod() -> Void { print("overriden method") } } // Works! ChildClass.someStaticMethod()

    Slide 97

    Slide 97 text

    Mutating Struct struct Person { var weigth : Int = 1 mutating func eat() { self.weigth += 1 } } var jack = Person(weigth: 50) jack.eat() If Struct modifies itself, add mutating Struct has automatic init for public properties

    Slide 98

    Slide 98 text

    Mutating Struct struct Person { var weigth : Int = 1 mutating func eat() { self.weigth += 1 } } let jack = Person(weigth: 50) jack.eat() Will fail! cannot use mutating member on immutable value: 'jack' is a 'let' constant

    Slide 99

    Slide 99 text

    Mutating Class class Person { var weigth : Int = 1 func eat() { self.weigth += 1 } } let jack = Person() jack.weigth = 40 jack.eat() mutating not needed No automatic init, you can use let here

    Slide 100

    Slide 100 text

    Lab

    Slide 101

    Slide 101 text

    Inheritance, Initialization, Deinitialization

    Slide 102

    Slide 102 text

    Inheritance • Class can inherit methods, properties and other from another class • Inheriting class is subclass, class it inherites is superclass • Class that does not inherit from another class is base class • Swift classes do not inherit from universal base class! • You can use AnyObject, that can represent an instance of any type • Classes can add property observers to inherited properties

    Slide 103

    Slide 103 text

    Class Inheritance class Human { var name : String = "" func sleep() { print("\(name) is sleeping") } func drink() { print("\(name) is drinking water") } func printMyInfo() { print("name = \(name)") } } class Programmer : Human { var salary : Int = 0 func implementCode() { print("\(name) is working") } override func drink() { print("\(name) is drinking energy drink") } override func printMyInfo() { super.printMyInfo() print("salary = \(salary)") } } var p = Programmer() p.salary = 4000 p.name = "jack" p.drink() p.printMyInfo()

    Slide 104

    Slide 104 text

    You can override properties too class ProjectManager { var salary : Int = 5000 func drink() { print("Project Manager is drinking water") } } class Programmer : ProjectManager { override var salary : Int { set { super.salary = newValue } get { return super.salary - 1000 } } override func drink() { print("Programmer is drinking energy drink") } } var p = Programmer() p.salary = 4000 print(p.salary)

    Slide 105

    Slide 105 text

    Initialization • init – methods are special methods that can be called when creating a new instance of particular type • Purpose is to ensure that objects are correctly initialized • Also deinitialization methods available • Classes and structures must set all stored properties when object is created • When setting the value in init, property is directly set, no observations are called • Swift provides automatic external name for every parameter in init. • External names must be used when using the init

    Slide 106

    Slide 106 text

    Simple (not working) init struct Color { var red, green, blue: Double init() {} } let halfGray = Color() Will fail, all properties must be initialized

    Slide 107

    Slide 107 text

    Compiles! Why? struct Color { var red, green, blue: Double? init() {} } let halfGray = Color() Optional Double, now it works..

    Slide 108

    Slide 108 text

    Compiles too.. struct Color { var red, green, blue : Double init() { self.red = 0.0 self.green = 0.0 self.blue = 0.0 } } let halfGray = Color()

    Slide 109

    Slide 109 text

    Using Default values struct Color { var red = 0.0 var green = 0.0 var blue = 0.0 init() {} } let halfGray = Color() If a property always takes the same initial value, provide a default value rather than setting a value within an initializer. It makes for shorter, clearer initializers and enables you to infer the type of the property from its default value.

    Slide 110

    Slide 110 text

    Initalizers with init parameters struct Color { var red, green, blue: Double init(red: Double, green: Double, blue: Double) { self.red = red self.green = green self.blue = blue } init(white: Double) { red = white green = white blue = white } } let magenta = Color(red: 1.0, green: 0.0, blue: 1.0) let halfGray = Color(white: 0.5)

    Slide 111

    Slide 111 text

    External Names struct Color { var red, green, blue : Double init(w white : Double) { self.red = white self.green = white self.blue = white } } let halfGray = Color(w: 0.5)

    Slide 112

    Slide 112 text

    Designated Initializers and Convenience Initializers in Classes • Designated Initializers • Primary initializers for a class / struct • Initializes all properties • Calls superclasses initializer • Every class must have at least one designated initializer • Use init(parameters) { .. } • Convenience Initializers • Secondary supporting initializers • You do not have to provide these • Use convenience init(parameters) { ... }

    Slide 113

    Slide 113 text

    Rules Image from Apple Swift documentation

    Slide 114

    Slide 114 text

    SImple Designated Init class Motor { } class Vehicle { var brand: String init(brand: String) { self.brand = brand } } class Car : Vehicle { var motor: Motor init(brand : String, motor: Motor) { self.motor = motor super.init(brand: brand) } override convenience init(brand : String) { let m = Motor() self.init(brand: brand, motor: m) } } var c1 = Car(brand: "Porsche", motor: Motor()) var c2 = Car(brand: "Skoda")

    Slide 115

    Slide 115 text

    Automatic Initializer Inheritance • Subclasses do not inherit initializers by default • If certain conditions are met, initializers are automatically inherited • Rule 1 • If your subclass doesn't define designated initializer, it automatically inherits all of its superclass designated initializers • Rule 2 • If your subclass provides an implementation of all of its superclasses designated initializers (either rule 1 or creating new ones) then it automatically inherites all of the superclass convenience initializers

    Slide 116

    Slide 116 text

    Example about Automatic Inheritance class A { var x : Int var y : Int init(x: Int, y: Int) { print("Designated A init()"); self.x = x self.y = y } convenience init() { print("Convenience A init()"); self.init(x: 0, y: 0) } } class B : A {} var b = B() Rule 1: If your subclass doesn't define designated initializer, it automatically inherits all of its superclass designated initializers Rule 2: If your subclass provides an implementation of all of its superclasses designated initializers (either rule 1 or creating new ones) then it automatically inherites all of the superclass convenience initializers Does it work?

    Slide 117

    Slide 117 text

    Safety Check 1 class A { var x : Int var y : Int init(x: Int, y: Int) { print("Designated A init()"); self.x = x self.y = y } convenience init() { print("Convenience A init()"); self.init(x: 0, y: 0) } } class B : A { var z : Int init(x: Int, y: Int, z: Int) { print("Designated B init()") self.z = z; super.init(x: x, y: y) } } var b = B(x: 0, y:0, z:0) Own properties must be initialized first!

    Slide 118

    Slide 118 text

    Safety Check 2 class A { var x : Int var y : Int init(x: Int, y: Int) { print("Designated A init()"); self.x = x self.y = y } convenience init() { print("Convenience A init()"); self.init(x: 0, y: 0) } } class B : A { var z : Int init(x: Int, y: Int, z: Int) { print("Designated B init()") self.z = z; super.init(x: x, y: y) self.x = 0 } } var b = B(x: 0, y:0, z:0) If accessing base classes properties, do it after super.init

    Slide 119

    Slide 119 text

    Overriding init class A { var x : Int init(x: Int) { self.x = x } } class B : A { var y : Int override init(x: Int) { self.y = 0 super.init(x:0) } init(x: Int, y: Int) { self.y = y super.init(x: x) } } notice the override

    Slide 120

    Slide 120 text

    Memberwise init for Structs struct Rectangle { var width = 0 var height = 0 } let r1 = Rectangle(width: 3, height: 4) let r2 = Rectangle(height: 4) Default inits if no init given

    Slide 121

    Slide 121 text

    Failable init struct Person { private var _age : Int init?(age: Int) { if age > 0 { self._age = age } else { return nil } } } if let s = Person(age: 7) { print("\(s)") } can return nil

    Slide 122

    Slide 122 text

    Required init class Person { init() { } } class Programmer : Person { init(salary: Int) { } } let a = Programmer(salary: 4000) //let b = Programmer() Programmer has only one init!

    Slide 123

    Slide 123 text

    Required init class Person { required init() {} } class Programmer : Person { init(salary: Int) {} required init() {} } let a = Programmer(salary: 4000) let b = Programmer() Subclasses must have

    Slide 124

    Slide 124 text

    Protocols

    Slide 125

    Slide 125 text

    Callbacks • Several ways of making callbacks • Closures • Anonymous functions that have access to local variables • Selectors (kind of depricated in Swift) • Function pointer passing functions. Not type-safe and it's obj-c feature. API uses it, so for legacy reasons, swift provides a way of passing selector function. • Delegate Protocols • Several callback methods!

    Slide 126

    Slide 126 text

    Selector class SelectorTest { func main { let selector : Selector = #selector(self.someFunc) self.test(selector); } func test(function: Selector) { performSelectorOnMainThread(function, withObject: self, waitUntilDone: true) } func someFunc(x : Int) { NSLog("Hello World"); } }

    Slide 127

    Slide 127 text

    Closures • Closures are like lambdas in Java / C# or blocks in Obj-C • Like mini-functions without a name • Example 1 reversed = sorted(names, { (s1: String, s2: String) -> Bool in return s1 > s2 }) • Example 2 func hello(a : Int, b: Int) -> Void { println(a + b) } func testClosures(m : (Int, Int) -> Void) { m(5,5) } testClosures(hello);

    Slide 128

    Slide 128 text

    Protocols • Define a blueprint of • methods • properties • Protocol can be adopted by a class, struct or enumeration • .. to provide the actual implementation

    Slide 129

    Slide 129 text

    Protocols and Delegate • Delegate refers to Delegation Design Pattern that uses protocols (let’s see this in a bit..) • Protocol is an interface that holds method declarations • When a class conforms to a protocol, it implements the protocol methods • Protocol methods can be mandatory or optional! • Using protocols (interfaces) you can define a contract that the implementor fulfills • If you have developed with Java: • protocol is an interface that may hold also optional methods!

    Slide 130

    Slide 130 text

    Example protocol Flyable { func fly() -> Void } class Animal {} class Bird : Animal, Flyable { func fly() { print("Bird flies") } } The first is inheritance, the rest are protocols

    Slide 131

    Slide 131 text

    Polymorphism protocol Flyable { func fly() -> Void } class Animal {} class Bird : Animal, Flyable { func fly() { print("Bird flies") } } class Airplane : Flyable { func fly() { print("Airplane flies") } } func fly(f : Flyable) { f.fly() } fly(f: Bird()) fly(f: Airplane()) Protocol type

    Slide 132

    Slide 132 text

    Properties • You can declare also a property to protocol • Get and Set • var width: Int { get set } • The property must be settable, cannot be let for example • Get • var width: Int { get } • The property can be settable!

    Slide 133

    Slide 133 text

    Properties protocol Shape { var width: Int { get set } } class Rectangle : Shape { } Does not conform to a protocol

    Slide 134

    Slide 134 text

    Properties protocol Shape { var width: Int { get set } } class Rectangle : Shape { var width = 0 } Now it does.. For Gettable & Settable Protocol Property, the requirement cannot be fulfilled by a constantly stored property or a read-only computed property.

    Slide 135

    Slide 135 text

    Properties protocol Shape { var width: Int { get set } } class Rectangle : Shape { let width = 0 } Contant variable, problem here For Gettable & Settable Protocol Property, the requirement cannot be fulfilled by a constantly stored property or a read-only computed property.

    Slide 136

    Slide 136 text

    Properties protocol Shape { var width: Int { get set } } class Rectangle : Shape { var _width = 0 var width: Int { get { return _width } set { if newValue > 0 { _width = width } } } } This works

    Slide 137

    Slide 137 text

    Properties protocol Shape { var width: Int { get set } } class Rectangle : Shape { var _width = 0 var width: Int { get { return _width } } } And now we have a problem...

    Slide 138

    Slide 138 text

    Properties protocol Shape { var width: Int { get } } class Rectangle : Shape { var width = 0 } Can also be settable!! Works..

    Slide 139

    Slide 139 text

    Delegation Pattern • The real power behind protocols comes when using polymorphism. • It’s possible to create pointer that points to whatever object as long as it conforms to protocol: • var x : Movable • You can define a message argument with the following argument type • func doSomething(x : Movable) • And now you can pass to this method whatever object as long as it’s conforming to this protocol!

    Slide 140

    Slide 140 text

    Delegation Pattern Example: GPS • CLLocationManager – class holds a following property • var delegate: CLLocationManagerDelegate • You can set the property • self.location = CLLocationManager() • self.location.delegate = ... • The delegate object can be what ever object as long as it’s conforming to CLLocationManagerDelegate • The CLLocationManagerDelegate holds several optional methods

    Slide 141

    Slide 141 text

    import Foundation import CoreLocation class LocationManager: NSObject, CLLocationManagerDelegate, ObservableObject { var location : CLLocationManager! @Published var done = false func fetch() { self.location = CLLocationManager() self.location.delegate = self self.location.requestWhenInUseAuthorization() self.location.startUpdatingLocation() print("start to fetch") } func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { let latitude = locations[0].coordinate.latitude let longitude = locations[0].coordinate.longitude done = true } } The protocol One of protocol's optional methods

    Slide 142

    Slide 142 text

    Enums and Exception Handling

    Slide 143

    Slide 143 text

    Simple Enum Example enum Day { case monday case tuesday case wednesday } let day : Day = Day.monday print(day) Outputs "monday"

    Slide 144

    Slide 144 text

    Simple Enum Example enum Day { case monday case tuesday case wednesday } func output(day: Day) { print(day) } output(day: Day.monday) output(day: .monday) You can omit "Day." because type is known.

    Slide 145

    Slide 145 text

    Raw value enum Day : String { case monday = "Mon" case tuesday = "Tue" case wednesday = "Wed" } func output(day: Day) { print(day.rawValue) } output(day: Day.monday) output(day: .monday) "Mon"

    Slide 146

    Slide 146 text

    Raw value enum Day : Int { case monday = 1 case tuesday case wednesday } func output(day: Day) { print(day.rawValue) } output(day: .monday) output(day: .tuesday) 1 2

    Slide 147

    Slide 147 text

    Error Handling with Enums enum MyError: Error { case maxOver case minUnder } func output(_ a: Int, _ b: Int) throws -> Int { let sum = a + b if sum > 100 { throw MyError.maxOver } else if sum < 0 { throw MyError.minUnder } return sum } do { let sum = try output(2,2) print(sum) } catch MyError.maxOver { print("Over max") } catch MyError.minUnder { print("Under min") }

    Slide 148

    Slide 148 text

    Error Handling with try? enum MyError: Error { case maxOver case minUnder } func output(_ a: Int, _ b: Int) throws -> Int { let sum = a + b if sum > 100 { throw MyError.maxOver } else if sum < 0 { throw MyError.minUnder } return sum } let sum = try? output(2,2) if let s = sum { print(s) } Returns now optional

    Slide 149

    Slide 149 text

    Opaque type

    Slide 150

    Slide 150 text

    Protocol - type protocol Flyable { func fly() -> Void } struct Bird: Flyable { func fly() -> Void { print("Bird") } } struct Airplane: Flyable { func fly() -> Void { print("Airplane") } } func giveFlyable() -> Flyable { return Bird() } let f = giveFlyable() f.fly() Returns protocol type

    Slide 151

    Slide 151 text

    Opaque - type protocol Flyable { func fly() -> Void } struct Bird: Flyable { func fly() -> Void { print("Bird") } } struct Airplane: Flyable { func fly() -> Void { print("Airplane") } } func giveFlyable() -> some Flyable { return Bird() } let f = giveFlyable() f.fly() Returns opaque type

    Slide 152

    Slide 152 text

    Protocol vs Opaque • Opaque types preserves type identity, protocol types do not • Opaque type always prefers to one specific concrete type • Protocol type can refer to many types as long as it is conforming to protocol

    Slide 153

    Slide 153 text

    Protocol type func giveFlyable() -> Flyable { return Bird() } var f = giveFlyable() f = Airplane() f.fly() f may contain Bird or Airplane

    Slide 154

    Slide 154 text

    Protocol type func giveFlyable() -> some Flyable { return Bird() } var f = giveFlyable() f = Airplane() f.fly() helloworld.swift:20:5: error: cannot assign value of type 'Airplane' to type 'some Flyable' f = Airplane()

    Slide 155

    Slide 155 text

    Protocol type func giveFlyable() -> some Flyable { return Bird() } var f = giveFlyable() f = Bird() f.fly() And it works now again...

    Slide 156

    Slide 156 text

    Protocols can have associated types protocol Flyable { associatedtype T var power : T { get } func fly() -> Void } The type can be determined later

    Slide 157

    Slide 157 text

    Adopting to Protocol struct Bird: Flyable { var power : Double func fly() -> Void { print("Bird flying with speed of \(power)") } } struct Airplane: Flyable { var power : Int func fly() -> Void { print("Airplane flying with speed of \(power)") } } func giveFlyable() -> Flyable { return Bird(power: 1.1) } var f = giveFlyable() f.fly() It is some object that conforms to the protocol. But what is the type of T? Swift cannot determinate this!

    Slide 158

    Slide 158 text

    Adopting to Protocol struct Bird: Flyable { var power : Double func fly() -> Void { print("Bird flying with speed of \(power)") } } struct Airplane: Flyable { var power : Int func fly() -> Void { print("Airplane flying with speed of \(power)") } } func giveFlyable() -> some Flyable { return Bird(power: 1.1) } var f = giveFlyable() f.fly() Opaque return type works... Will return always Bird with type of Double

    Slide 159

    Slide 159 text

    Recap • Protocol type can have any object as long as it's conforming to the protocol • This does not work with associated type, concrete type information is missing • use some keyword and let the implementation determinate the concrete type

    Slide 160

    Slide 160 text

    SwiftUI var body: some View { VStack() { Text("A") Text("B") } } VStack>

    Slide 161

    Slide 161 text

    Extensions

    Slide 162

    Slide 162 text

    Extensions • Extensions add new functionality to an existing class, structure, enumeration or protocol • Add properties • Define methods • Define inits • ...

    Slide 163

    Slide 163 text

    Example: String extension String { func isPalindrome() -> Bool { return self == String(self.reversed()) } } print("saippuakauppias".isPalindrome())

    Slide 164

    Slide 164 text

    How would you implement this? 3.repetitions { print("Hello!") } Int Add extension

    Slide 165

    Slide 165 text

    How would you implement this? 3.repetitions(task: { print("Hello") }) Without trailing closure

    Slide 166

    Slide 166 text

    How would you implement this? 3.repetitions { print("Hello!") } extension Int { func repetitions(task: () -> Void) { } } Argument is function

    Slide 167

    Slide 167 text

    How would you implement this? 3.repetitions { print("Hello!") } extension Int { func repetitions(task: () -> Void) { for _ in 0..