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)
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...
"
}
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))
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!
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
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
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
• ...