Open menu with table of contents iOS Development - Swift Fundamentals
Logo of Stuttgart Media University for light theme Logo of Stuttgart Media University for dark theme
Mobile Application Development 2

iOS Development - Swift Fundamentals

Stuttgart Media University

1 Agenda

  • Quick overview of Objective-C
  • Swift Basics
  • Swift Exercise

2 Objective-C

  • Developed by Brad Cox and Tom Love in the early 80s (StepStone)
  • Object oriented extension to ANSI C
  • Strict superset of C
    • Can be mixed with C and C++
  • Dynamic runtime
  • Loosely typed (if you want it)
  • Inspired by Smalltalk
  • Goal: "As fast as C but as beautiful as Smalltalk"

center 40%

83%

3 History of Objective-C

  • Steve Jobs licensed Objective-C in 1988
  • AppKit and Foundation were developed
  • Development base for NeXTStep UI
  • Development Tools Projekt Builder and Interface Builder

4 Well known Objective-C Projects

  • ...?

5 Well known Objective-C Projects

  • Tim Berners Lee: First Web-Server & Web-Browser (1990)
  • John Carmack: Doom and predecessor Wolfenstein 3D
  • Project Builder and Interface Builder are the basis of Xcode
  • NeXTStep and OpenStep are the basis of MacOS X and iOS
  • iWork (Keynote, Numbers, Pages)

center 60%

[Source:Wikipedia](https://de.wikipedia.org/wiki/Tim_Berners-Lee)

6 Objective-C

  • Until 2012 Objective-C was constantly updated
  • Compiler Clang on basis of LLVM
  • Objective-C is and stays a modern programming language
  • TIOBE index: Objective-C was language of the year 2011 and 2012*
  • Q4 2014: Swift is introduced as new language for iOS and Mac OS X development by Apple
  • Q4 2015: Swift 2.0 was released changing some parts of the syntax and introducing error handling
    • with try / catch / throws. Swift is OpenSource
  • Q4 2016: Swift 3.0 released with major changes
  • Q3 2017: Swift 4.0 released
  • Q1 2019: Swift 5 released with ABI stability
  • The rest is history...

7 Objective-C Example

  • Short Objective-C application (using Foundation) coding demo using CLang compiler frontend:
    • clang -fobjc-arc testapp.m -o testapp

center

8 Objective-C Files

  • Separation of public declaration and implementation in header and source files (like in C)
Extension Source Type
.h Header files. Header files contain class, type, function, and constant declarations.
.m Source files. This is the typical extension used for source files and can contain both Objective-C and C code.
.mm Source files. A source file with this extension can contain C++ code in addition to Objective-C and C code. This extension should be used only if you actually refer to C++ classes or features from your Objective-C code.

9 Class Interface

  • Class declaration in *.h
@interface MyClass : NSObject
{
    int         count;
    id          data;
    NSString*   name;
}
- (id)initWithString:(NSString*)aName;
+ (MyClass*)createMyClassWithString:(NSString*)aName //Class method;
@end

10 Class Interface

  • Class implementation in *.m
@implementation MyClass

- (id)initWithString:(NSString *)aName
{
    self = [super init];
    if (self) {
        name = [aName copy];
    }
    return self;
}

+ (MyClass *)createMyClassWithString: (NSString *)aName
{
    return [[self alloc] initWithString:aName] ;
}
@end

11 NSObject

  • NSObject is root class (similar to Object class in Java)
  • Provides functionality for
    • Memory management (allocation, release)
    • Object equality
    • Introspection
  • Part of the Foundation framework

12 Using a class

  • Create an instance of a class in two steps:
    • Dynamically allocate memory
    • Initialize the allocated memory with values
//create an Object of SomeClass:
id anObject = [[SomeClass alloc] init];

//Example init method implementation in NSObject:
- (id)init {

    self = [super init];
    if (self) {
        //initialisation of Object
    }

    return self;
}

13 Using Objects

  • Object initialization example using NSString object
NSString* text1 = [[NSString alloc] initWithCString: "Hello World!" encoding: NSUTF8StringEncoding];

NSString* text2 = @"Hello World!"; //short for upper statement
NSLog(@"text 1 = %@", text1); //%@ placeholder for objects
NSLog(@"text 2 = %@", text2);

NSLog(@"text2.length = %ld", text2.length);

14 Methods

  • Method declaration
    • Instance method identifier: minus (-)
    • Class method type identifier: plus (+)

center 60%

Source:Stackoverflow

15 Methods

  • Calling a method is done by messaging an object
  • A message is the method signature plus parameter information
  • Messages are dispatched dynamically, facilitating the polymorphic behavior of Objective-C classes
  • Messages are enclosed by brackets and look like this:
 [myArray insertObject:anObject atIndex:0];

16 Messaging Terminology

  • Message expression
    • [receiver method:argument]
  • Message
    • [receiver method:argument]
  • Selector
    • [receiver method:argument]
  • Method
    • The code selected by a message

17 Object Messaging Examples

  • Messages can be nested to avoid declaring numerous local variables
  • The return value from each nested message is used as a parameter, or as the target, of another message
[[myAppObject theArray] insertObject: [myAppObject objectToInsert] atIndex: 0];

18 Object Messaging Examples

// message without argument
[receiver message];

// message with single argument
[receiver message: argument];

// message with multiple arguments
[receiver message: arg1 argument2: arg2];

// receiving a return value
int status = [receiver message];

// message with a variable number of arguments
[receiver makeGroup: group, memberOne, memberTwo, memberThree];

19 Object Messaging Examples

  • Sending messages to the class is the same as sending them to an instance, you only need to use the class name
// nil is essentially the same as NULL

NSMutableArray *myArray = nil;

// Create a new array and assign it to the myArray variable.

myArray = [NSMutableArray array];

20 Dynamic Typing

  • Supports strongly and weakly (dynamic) typed variable declarations
 Person* myPerson;  // Strong typing

 id myObject;  // Weak typing
  • Dynamic type id is completely unrestrictive
  • The type of an object is only determined at runtime
  • Allows for introspection and dynamic binding

21 Dynamic Binding

  • Supports (dynamic) binding of methods at runtime Allows high flexible programming paradigms
//Dynamic binding example
@interface ClassA : NSObject {…}
- (void) doSomething;
@end

@interface ClassB : NSObject { …}
- (void) doSomething;
@end

// anywhere
id object = … // An object of an arbitrary class
[object doSomething]; // polymorph between ClassA und ClassB

22 Hands On Objective-C

Please open the terminal and create your first Objective-C project.

  • Exercise: Create a new Objective-C project that prints "Hello World" to the console

Exercise

23 Swift vs Objective-C

Objective-C:

NSString *helloWorld = @"Hello World";
NSLog(@"%@", helloWorld);

Swift:

var str = "Hello World"
print(str)

24 Swift Language Goals

  • Easy to use, like a scripting language (Python, JS)
  • Powerful functional approach
  • Fully object oriented
  • Completely compatible with Objective-C (and C)
  • Designed to avoid programming mistakes

25 Whats New?

  • Following language concepts are new compared to Objective-C and borrowed from different languages:
    • Optionals (optional return values, similar to python)
    • Closures (similar to Block Objects or closures in Lisp, C#)
    • Tuples (similar to multiple returns in python)
    • Generics (similar to Java Generics or C++ Templates)
    • Type Inference (similar to JavaScript) -> Swift is a type safe language

26 Swift Language Fundamentals

  • Variables and Constants
  • Optionals
  • Basic Data Types
  • Control Flows
  • Functions & Closures
  • Classes
  • Exception Handling with Try / Catch & Guard
  • Protocol Extensions

More background information: Swift Language History

Learn Swift: Swift Language Guide

27 Variables

  • Variables are declared using the keyword var
var myvariable = 0
  • Variables are strongly typed
  • If type is not explicitly defined, it is inferred automatically when a value is assigned
  • Type annotation can be used to define the type explicitly:
var myvariable: Int = 0

28 Variables

var name = "Name" // Type is inferred as String

var age = 38 // Type is inferred as Int

var weight = 90.5 // Type is inferred as Double

var myvariable: Int // Type annotation defining type Int

var myName: String = "HdM"

29 Constants

  • Constants are declared using the keyword let
let myconstant = 10
  • They must be initialized (at some time, before usage)
  • Are guaranteed to always retain the value they were first assigned
  • They can not be changed once they are set
  • Multiple constants or variables can be declared in one line separating them with commas:
var myvariable = 0, yourvar = 1, anothervar = 3

30 Optionals

  • Qualifier for a variable (own data type)
  • Indicates the variable may not have a value set
  • If non-optional, no null (or nil in swift) values can be set
  • Use a ? after the Type to declare it as optional
  • Use a ! to "unwrap" the optional and retrieve the contained object
var rabbit: String? //declares optional String
... //rabbit = "running"
if (rabbit != nil){
    print("Rabbit is \(rabbit!)") //unwraps Optional
} else {
    print("Rabbit is nil")
}

31 Basic Data Types

  • Integer
  • Float & Double
  • Boolean
  • Strings & Characters
  • Arrays
  • Tuples

32 Int

  • Swift provides signed and unsigned integers in 8,16,32 and 64 bit forms
var smallInt: UInt8 = 5
var largertInt: Int16 = 10
var evenLargerInt: Int32 = 100
var biggestInt: UInt64 = 1000
  • To access the minimum and maximum values of each integer type they provide min and max properties
UInt8.min //0
UInt8.max //255
Int16.min // -32768
Int16.max // 32768
  • On a 32-bit platform, Int is the same size as Int32 on 64-bit it is the size of Int64 (same is true for UInt)

33 Float, Double

  • Floating point number are either Float (32-bit) or Double (64-bit)
var mySmallFloat: Float = 2.34352
var myBigFloat: Double = 3.42323
  • When inferring the type of a floating-point number, Swift alway chooses Double
  • When combining integer and float, Double is also inferred
let pi = 3 + 0.14159
  • To make reading numbers more easy, numeric literals can be padded with extra zeros or contain underscores
let paddedDouble = 000123.456
let oneMillion = 1_000_000
let justOverOneMillion = 1_000_000.000_000_1

34 Boolean

  • Swift has a basic Boolean type called Bool
let hdmIsGreat = true
let swiftIsBoring = false
  • In contrast to C or Objective-C, non-boolean values can not be substituted for Bool. This would not work:
let i = 1
if i {
    //will not compile and report an error
}
  • An alternative would be
let i = 1
if i==1 {
    //this works
}

35 Range

A Range or CountableRange (since Swift 3.0) is a type in Swift that defines a number of elements that can be iterated over, e.g. a number of integer values or String.Index values The Range can be created using the range operator: ClosedRange operator: ... Range operator: ..<

let myFromZeroTo5Range = 0...5 //CountableClosedRange(0...5)
let myFromZeroToSmallerSixRange = 0..<6 //CountableRange(0..<6))

Since Swift 3.0 ClosedRange (...) and Range (..<) are two different types which can not be converted into each other.

36 Strings & Characters

Swift Strings and Characters are value types, Unicode compliant and easy to use

let emptyImmutableString = ""
var emptyMutableString = ""
var emptyString = String()
let sparklingHeart = "\u{1F496}"

String values can be constructed by passing an array of Characters

let catCharacters: [Character] = ["C", "a", "t", "!", "🐱"]
let catString = String(catCharacters)

Concatenation of Strings and Characters is simple

let string1 = "Hello "
let string2 = "HdM"
let char1: Character = "!"

var concatenatedString = string1 + string2 //"Hello HdM"
concatenatedString.append(char1) // "Hello HdM!"

37 Strings & Characters

String interpolation allows to create a new String from multiple variables or literals

let multiplier = 3
let message = "\(multiplier) times 2 is \(multiplier*2)" //„3 times 2 is 6“

Expressions in the parentheses cannot contain double quotes, backslashes, a carriage return or line feed You can call functions within the parentheses

func getHint() -> String {
    return "special hint"
}
let newmessage = "New hint: \(getHint())" //„New hint: special hint“

38 Strings & Characters

The property „characters“ allows you to iterate over all characters in a String

for letter in string {
    print("\(letter)")
}

Use count() to count Chars

string.count // 19

Use can create a range to access Characters of a part of a String

let range = string.index(string.startIndex, offsetBy: 5)..<string.index(before: string.endIndex)

for mindex in string.indices[range] {
    print("\(string[mindex])",terminator: "1")
}

39 Strings & Characters

To modify strings, you can use insert(), remove() and removeSubrange()

var myString = "Hello HdM"

var idx = myString.index(myString.endIndex, offsetBy: -2) //7

myString.remove(at: idx) // „Hello HM“

let r = myString.index(myString.startIndex, offsetBy: 5)..<myString.endIndex

myString.removeSubrange(r) // „Hello“

myString.insert("!", at: myString.endIndex) //"Hello HM!"

40 Strings & Characters

String and Character equality is checked using the „equal to“ operator (==) Strings are equal if they have the same linguistic meaning and appearance, even if they are composed from different Unicode scalars

let eAcuteQuestion = "Voulez-vous un caf\u{E9}?"
let combinedEAcuteQuestion = "Voulez-vous un caf\u{65}\u{301}?"
if eAcuteQuestion == combinedEAcuteQuestion {
    print("\(eAcuteQuestion) and \(combinedEAcuteQuestion) are considered equal")
}
// "Voulez-vous un café? and Voulez-vous un café? are considered equal"

Further you can use fully unicode.

let β = 3 * t - r * sin(φ) * cos(θ)

41 Strings & Characters

You can check the prefix or suffix of a String using hasPrefix() and hasSuffix()

let stringArray = ["1st String of 2","2nd String of 2"]

for string in stringArray {
    if string.hasPrefix("1st") {
        print("String starting with 1st: \(string)")
    }

    if string.hasSuffix("2") {
        print("String ending with 2: \(string)")
    }
}

42 Enumerations

  • An enumeration defines a common type for a group of related values and enables you to work with those values in a type-safe way within your code
enum GraphicalObjects {
    case Circle
    case Rectangle
    case Polygon
}

var go = GraphicalObjects.Circle

if go == GraphicalObjects.Circle {
    print("is a Circle")
} else if go == .Rectangle {
    print("is a Rectangle")
} else {
    print("is a Polygon")
}

43 Arrays - Introduction

Arrays are next to sets and dictionaries the mostly used collections in swift To create a mutable array, assign it to a variable (e.g. var myArray)

var shoppingList = [String]()

Initialize directly by writing:

var shoppingList = ["Apples", "Pears", "Bread", "Milk"]

44 Arrays - Appending items

Appending items to an Array

shoppingList.append("Soap")
//or
shoppingList += ["Juice"]

Adding Arrays and creating new ones

var familyList = shoppingList + ["Cornflakes","Ice Cream"]

Removing items from an Array

shoppingList.remove(at: 2)
shoppingList.removeLast()
shoppingList.removeAll(keepingCapacity: true)

45 Arrays - Check if empty

Check if an Array is empty

if shoppingList.isEmpty {
    ...
}

Retrieve a certain item or a part of the Array

shoppingList[5] //-> "Cornflakes"
shoppingList[1...3] //["Pears", "Bread", "Milk"]

46 Tuples - Introduction

Tuples group multiple values into a single compound value

let httpStatus = (404, "Not Found")

Each single value is accessible by a number, e.g.:

httpStatus.0 // 404
httpStatus.1 // "Not Found"

Tuples can be decomposed into their separate values

let (statusCode, description) = httpStatus
print("Statuscode: \(statusCode) means: \(description)")

You can name the elements in a tuple and access them using the names

let newHttpStatus = (code: 200, description: "OK")
print("code: \(newHttpStatus.code)")
print("description: \(newHttpStatus.description)")

47 Control Flow - Introduction

  • Loops: for, while, repeat-while
  • Conditional statements: if, switch, where, assert

48 For-In-Loop - Iterating over an Array

Iterating over an Array

var familyList = ["Milk", "Bread","Soap","Juice"]
for item in familyList {
    print(item)
}

Iterating with index and value

for (index,value) in familyList.enumerated() {
    print("item nbr. \(index + 1) is: \(value)")
}

49 For-Loop - Iterating over a range

Since Swift 3.0 for-loops look like this:

for index in 0 ..< 3 {
    print("index is \(index)")
}

C-style loops are not supported anymore

50 While-Loop - Introduction

Use the while loop to iterate while a condition is true

var shoppingList = ["Apples","Pears","Bread","Milk"]
while !shoppingList.isEmpty {
    print("remove one item from list")
    shoppingList.removeLast()
}

Use do-while to test the condition after executing the statements

shoppingList = ["Apples","Pears","Bread","Milk"]
repeat {
    shoppingList.removeLast()
} while !shoppingList.isEmpty

51 If-Statement - Introduction

Test a condition using if The else-if and final else clause is optional

var temperatureInFahrenheit = 90
if temperatureInFahrenheit <= 32 {
    print("It's very cold. Consider wearing a scarf.")
} else if temperatureInFahrenheit >= 86 {
    print("It's really warm. Don't forget to wear sunscreen.")
} else {
    print("It's not that cold. Wear a t-shirt.")
}
// prints "It's really warm. Don't forget to wear sunscreen."

52 Switch-Statement - Introduction

  • Use switch to compare a value against several possible matching patterns
  • In contrast to C and Objective-C the entire switch statement finishes its execution as soon as the first matching switch case is completed (no fall-through to other cases)
    • Break statement is not required but can still be used
let someCharacter: Character = "e"
switch someCharacter {
case "a", "e", "i", "o", "u":
    print("\(someCharacter) is a vowel")
case "b", "c", "d", "f", "g", "h", "j", "k", "l", "m",
"n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z":
    print("\(someCharacter) is a consonant")
default:
    print("\(someCharacter) is not a vowel or a consonant")
}

53 Switch With Tuple

  • A switch case can use a where clause to check for additional conditions
  • In the following example, a Tuple representing a Point in a coordinate system is checked using a switch statement
let yetAnotherPoint = (1, -1)
switch yetAnotherPoint {
case let (x, y) where x == y:
    print("(\(x), \(y)) is on the line x == y")
case let (x, y) where x == -y:
    print("(\(x), \(y)) is on the line x == -y")
case let (x, y):
    print("(\(x), \(y)) is just some arbitrary point")
}
// prints "(1, -1) is on the line x == -y"

54 Hands On Swift - Part 1

Exercise

55 Functions & Closures - Introduction

  • To declare a function use the keyword func. To call a function using the name followed by the parameters in parentheses
  • The parameters alway are defined with a name followed by a colon and the type.
  • The return value is declared after the ->
  • See chapter on Functions in the Swift documentation
func greet(name: String, day: String) -> String {
    return "Hello \(name), today is \(day)."
}
greet(name: "Bob", day: "Tuesday")

56 Functions & Closures - Parameters

  • Parameters of a function can have a name and a description. The description (day) is obligatory and the name (d) is optional. If no name is given, the description is automatically used as name for the parameter
  • Within the function the parameter is referenced by the name
func greet(name: String, day d: String) -> String {
    return "Hello \(name), today is \(d)."
}
greet(name: “Bob", day: "Tuesday")

57 Functions & Closures - Returning multiple values

It is possible to return multiple values from a function using Tuples

func getGasPrices() -> (Double, Double, Double) {
    return (3.59, 3.69, 3.79)
}
getGasPrices()

Functions can take a variable number of arguments

func sumOf(numbers: Int...) -> Int {
    var sum = 0
       for number in numbers {
        sum += number
       }
    return sum
}
sumOf()
sumOf(numbers: 42, 597, 12)

58 Functions & Closures - Nested functions

  • Functions can be nested
func returnFifteen() -> Int {
    var y = 10
    func add() {
        y += 5
    }
    add()
    return y
}
returnFifteen()

59 Functions & Closures - Returning functions

  • Functions are first class types and can be returned as a value
func makeIncrementer() -> ((Int) -> Int) {
    func addOne(number: Int) -> Int {
        return 1 + number
    }
    return addOne
}
var increment = makeIncrementer()
increment(7)

60 Functions & Closures - Passing functions as parameters

  • Functions can take other functions as a parameter
func hasAnyMatches(list: [Int], condition: (Int) -> Bool) -> Bool {
    for item in list {
        if condition(item) {
            return true
        }
    }
    return false
}

func lessThanTen(number: Int) -> Bool {
    return number < 10
}

var numbers = [20, 19, 7, 12]
hasAnyMatches(list: numbers,condition: lessThanTen)

61 Functions & Closures - Closures

  • Closures are functions without a name surrounded by braces
  • The keyword in is used to separate arguments and return type from the body of the closure
var numbers = [20, 19, 7, 12]
numbers.map({
    (number: Int) -> Int in
    let result = 3 * number
    return result
})

62 Structs & Classes - Introduction

  • Structures and classes are general-purpose, flexible constructs that become the building blocks of your program’s code.
  • You can properties and methods using the same syntax you use to define constants, variables, and functions.
  • Structs are very similar to Classes, but lack certain capabilities, e.g. inheritance and type casting
struct Resolution {
    var width = 0
    var height = 0
}

// create an instance

let someResolution = Resolution()

63 Structs & Classes - Introduction

  • A Class is defined using the keyword class
class Shape {
    var numberOfSides = 0
    func simpleDescription() -> String {
        return "A shape with \(numberOfSides) sides."
    }
}

64 Classes - definition

  • A Class is defined using the keyword class
class Shape {
    var numberOfSides = 0
    func simpleDescription() -> String {
        return "A shape with \(numberOfSides) sides."
    }
}
  • An instance is created by putting parentheses after the class name
let myShape = Shape()
myShape.numberOfSides = 10
myShape.simpleDescription()

65 Classes - Initializer

  • A Class should always have an initializer (Java: Constructor)
  • To create an initializer use the keyword init
class NamedShape {
    var numberOfSides: Int = 0
    var name: String

    init(name: String) {
        self.name = name
    }

    func simpleDescription() -> String {
        return "A shape with \(numberOfSides) sides."
    }
}

let s = NamedShape(name: "MyShape")

66 Properties - Introduction

  • Properties in Swift are like member variables with a getter and setter method in Java
  • Swift Properties combine Objective-C’s instance variables and properties in one
  • Properties can be constant, variable or computed

center 70%

67 Properties - Getter and Setter

  • Properties can define a getter and a setter

center 70%

68 Protocols in Swift - Introduction

  • A Protocol is in Swift what an Interface is in Java
  • It defines a number of requirements that need to be fulfilled by the implementing classes
    • Property requirements - defines Properties that need to be implemented
    • Method requirements - defines Methods that need to be implemented

69 Protocols in Swift - Definition

  • Protocols are defined very similar to classes and structures
  • To implement a Protocol in a class you declare it like this:
protocol SomeProtocol {
    // protocol definition goes here
}

class SomeClass: SomeSuperClass, FirstProtocol, SomeProtocol {
    // class definition goes here
}

70 Protocols in Swift - Property requirements

  • Property requirements are declared as variable properties and indicate if they are gettable or settable:
protocol SomeProtocol {

    // a settable Property must be implemented using
    // var in the implementing class
    var mustBeSettable: Int { get set }

    // a only gettable Property should be implented using let
    var doesNotNeedToBeSettable: Int { get }

}

71 Protocols in Swift - Method requirements

  • Method requirements are declared like this (like a normal method declaration just without curly braces and implementation):
protocol RandomNumberGenerator {

    func random() -> Double

}

72 Hands On Swift - Part 2

Exercise

73 Assertions - Introduction

  • An assertion is a runtime check that a logical condition evaluates to true
  • Assertions can be used to debug your code
  • Assertions are written by using the global assert() function
let age = -3
assert(age >= 0, "A person's age cannot be less than zero")
// this causes the assertion to trigger, because age is not >= 0

74 Exception Handling Try / Catch & Guard

class FatherChristmas {

    enum DeliveryError : Error {
        case NoPresentsRemaining
    }

    var numberOfPresents = 0

    func deliverPresents() throws {
        guard numberOfPresents > 0 else {
            throw DeliveryError.NoPresentsRemaining
        }
        print("Presents delivered")
    }
    func itIsChristmasEve(){
        do {
            try deliverPresents()
        } catch DeliveryError.NoPresentsRemaining{
            print("Could not deliver presents!")
        } catch {
            print("Unknown error")
        }
    }

}
let fatherChristmas = FatherChristmas()
fatherChristmas.itIsChristmasEve()

75 Protocol Extensions - Introduction

  • Allows to add functionality to existing classes or protocols
//this protocol defines the "description" method used by many classes
extension CustomStringConvertible {
    var shoutyDescription: String {
        return "\(self.description.uppercased())!!!"
    }
}

let greetings = ["Hello", "Hi", "Yo yo yo"]

print("\(greetings.description)")

    // prints "["HELLO", "HI", "YO YO YO“]!!!\n"

print("\(greetings.shoutyDescription)")

76 Asynchronous Functions - Introduction

More information on asynchronous functions can be found here

77 Swift is OpenSource