73
COMP228 [& 327] App Development Session: 2019-2020 Lecture Set 1 - Swift Introduction Part II [ last updated: 02 Oct 2019 ] 55 Illustration credit: vecteezy.com

COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

  • Upload
    others

  • View
    7

  • Download
    0

Embed Size (px)

Citation preview

Page 1: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

COMP228 [& 327] App Development Session: 2019-2020Lecture Set 1 - Swift Introduction Part II

[ last updated: 02 Oct 2019 ] 55Illustration credit: vecteezy.com

Page 2: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

56

Classes and Structures• The building blocks of your project’s code• Properties and Methods use the standard syntax you’re used to• Unlike objective C, no separate interface and implementation files!!

• Classes and Structures - have some similarities• Properties, methods, subscripts, initialisers

• In addition Classes have…• Inheritance. Type Casting. Deinitialisers. Reference Counting

Page 3: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

57

Classes and Structures

• Defining a Class or Structure defines a brand new Swift type• Instances of classes are reference types, structures are value types

• what does that mean?

class SomeClass { // class definition goes here } struct SomeStructure { // structure definition goes here }

Page 4: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

58

Classes and Structures• Value Types (Structs):

• copied when passed as an argument to a method (where they are immutable, unless you specify mutating in the parameter list)

• copied when assigned to a different variable• when assigned to a variable with let they are immutable

struct myStruct { var item1 = "" var item2 = 30.5}

func myMethod(s: myStruct ){ s.item1 = "testing"}var myS = myStruct()

myS.item2 = 70.9

print(myS.item2)

Cannot assign to property: 's' is a 'let' constant

Page 5: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

59

Classes and Structures• Instances of classes are reference types, structures are value types

class myClass { var name: String = "" }

let person1 = myClass() //create an instance of the class person1.name = "Phil" let person2 = person1 //assign person1 instance to person2 person2.name = "Terry" print(person2.name) //prints “Terry" (of course) print(person1.name) //but so does this (so, person1 === person2)

struct myStruct { var name: String = "" }

var person1b = myStruct() //create an instance of the struct person1b.name = "Phil" var person2b = person1b //assign person1b instance to person2b person2b.name = "Terry" print(person2b.name) //prints “Terry" (of course) print(person1b.name) //prints “Phil” (person1b != person2b)

Single instance!

Assignment creates a second

instance!

A Struct:

A Class:

Page 6: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

The Foundation Framework

60

A quick aside…

Page 7: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

61

Foundation Framework

• Defines a base layer of classes for use in creating applications (including NSObject root class)

• Supports all the underlying (common) classes

• Common to all Apple platforms (macOS, iOS, tvOS etc)

• Provides object wrappers for primitive types and collections

• Provides support for internationalisation and localisation with the use of dynamically loaded bundles

• Facilitated access to various lower level services of the operating system, including threads, file system, IPC etc

• Practically all Swift and Objective C applications include this framework (via e.g. UIKit)

Page 8: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

62

Foundation Framework

• Fundamentals:• Numbers, Data, Basic Values; Strings and Text; Collections; Dates and Times; Units and Measurement; Data Formatting; Files and Sorting

• App Support:• Task Management; Resources; Notifications; App Extensions Support; Errors and Exceptions; Scripting Support.

• Files and Data Persistence:• File System; Archives and Serialisation; Preferences; Spotlight; iCloud

• Networking:• URL Loading System; Bonjour

• Low-Level Utilities:• XPC; Object Runtime; Processes and Threads; Streams, Sockets and Ports

Cocoa & Cocoa Touch

- the application development

environments for OS X (now macOS) and iOS

respectively.

- Cocoa Touch includes the Foundation and UIKit frameworks.

• Provides a base layer of functionality for MacOS, iOS, watchOS and tvOS apps.

Page 9: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

63

Foundation Framework• Several of Swift’s standard types are bridged to Foundation classes

• String => NSString

• Array => NSArray

• Set => NSSet

• Dictionary => NSDictionary

• Means that we can utilise some of the features available to the Foundation classes but in general avoid the overhead of Foundation.

• In early releases of Swift, missing functionality provided by Foundation

Page 10: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

64

Classes and Structures• In Objective C, Dynamic Binding was used• Foundation class types are objects - with the usual object

overhead (e.g. string concat).

• flexible but slow• Swift implements most of the types from Foundation

framework as standard Swift types based on Structures• potentially much faster (courtesy of copy on write)

NSString *str = @"hello,";str = [str stringByAppendingString:@" world"];

we now return you to…

Page 11: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

65

Classes and Structures

• objects are copied only if and when the program attempts to change a value in them.

• Accessors have effectively a pointer to the same data storage, but far below the level of the language, in the computer’s MMU.

• While the data is physically stored as one instance in memory, in the application, these values are separate

• Physical separation is enforced by copy on write only if needed.

Copy on Write

Page 12: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

66

Classes and Structures

• Create Instances of a Class (or Struct)

struct Resolution { var width = 0 //inferred as an Int var height = 0 //ditto } class VideoMode { var resolution = Resolution() var interlaced = false //inferred as a Boolean var frameRate = 0.0 //inferred as a Double var name: String? //initialised to nil }

var someResolution = Resolution()

let someVideoMode = VideoMode()

• New instance with ( ) assigns default values to any property of the Class or Struct

Page 13: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

67

Classes and Structures

struct Fahrenheit { var temperature: Double init() { temperature = 32.0 } } var f = Fahrenheit() print("The default temperature is \(f.temperature)° Fahrenheit") // Prints "The default temperature is 32.0° Fahrenheit"

• Initialisers - called when new instance created.• and deinitialisers - called when deallocated

• Simplest initialiser defined like an instance method with no parameters. method named init( )

• For this simple case don’t need an init( ) - can simply assign this default value when var is declared.

struct Fahrenheit { var temperature = 32.0 }

Page 14: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

68

Properties in Classes and Structures

struct Temperature { var celsiusValue: Double var fahrenheitValue: Double { get { let temp = ((celsiusValue / 5) * 9) + 32.0 return temp } } var kelvinValue: Double { get { let temp = celsiusValue + 273.15 return temp } } init(celsius:Double) { celsiusValue = celsius } init(fahrenheit: Double) { celsiusValue = ((fahrenheit - 32.0) / 9) * 5 } init(kelvin: Double) { celsiusValue = kelvin - 273.15 }}var f = Temperature(celsius: 36.9) print("Body temperature is \(f.celsiusValue)° Celsius, \(f.fahrenheitValue)° Fahrenheit")print("and \(f.kelvinValue) Kelvin")

• Simple properties can be declared as usual with let or var• We can also have Computed properties

Page 15: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

69

Classes and Structures

struct Celsius { var temperatureInCelsius: Double

init(fromFahrenheit fahrenheit: Double) { temperatureInCelsius = (fahrenheit - 32.0) / 1.8 } init(fromKelvin kelvin: Double) { temperatureInCelsius = kelvin - 273.15 } } let boilingPointOfWater = Celsius(fromFahrenheit: 212.0) // boilingPointOfWater.temperatureInCelsius is 100.0 let freezingPointOfWater = Celsius(fromKelvin: 273.15) // freezingPointOfWater.temperatureInCelsius is 0.0

• Initialisation parameters - if used, define types and names of values to customise initialisation process

Argument NameArgument

label

Page 16: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

70

Classes and Structures

struct Celsius { var temperatureInCelsius: Double init(fromFahrenheit fahrenheit: Double) { temperatureInCelsius = (fahrenheit - 32.0) / 1.8 } init(fromKelvin kelvin: Double) { temperatureInCelsius = kelvin - 273.15 } init(_ celsius: Double) { temperatureInCelsius = celsius } } let bodyTemperature = Celsius(37.0) // bodyTemperature.temperatureInCelsius is 37.0

let freezingPointOfWater = Celsius(celsius: 0.0) // the above line generates an error

• Initialisation parameters argument label - if you don’t want one put “_” in the definition

argument labels ‘(celsius:)’ do not match any available overloads

Page 17: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

71

Classes and Structures

• Why is this output?• What’s happening at (A)?• What will transform the output as requested?

COMP327 (mobile computing) exam question from 2017

Page 18: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

72

Classes and Structures

struct SomeStructure { var testVar = 0 func addToVar (_ amount: Int) { testVar += amount }}

• By default, the properties of a value type (e.g. a Struct) cannot be modified from within its instance methods.

struct SomeStructure { var testVar = 0 mutating func addToVar (_ amount: Int) { testVar += amount }}

• If you *need* to be able to do this, mark the method as mutating

Left side of mutating operator isn't mutable: 'self' is immutable

Page 19: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

73

Classes and Structures

struct SomeStructure { var testVar = 0 mutating func addToVar (_ amount: Int) { testVar += amount }} let a1 = SomeStructure()a1.addToVar(30)

• In instances of structures created with let, you cannot change var properties.

class SomeClass { var testVar = 0 func addToVar (_ amount: Int) { testVar += amount }}

let a2 = SomeClass() //a2 is a constanta2.addToVar(30) //but we can modify its properties

• In instances of classes created with let, you can modify var properties.

Cannot use mutating member on immutable value: 'a1' is a 'let' constant

Page 20: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

74

Classes and Structures

• First example

Summary:

Can change properties in its instance methods can change its properties

Classes made with let Yes Yes

Classes made with var Yes Yes

Structs made with let No No

Structs made with var No (unless you add mutating to the method) Yes

Page 21: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

75

Enums

enum StarWarsRobot { case r2_d2 case c_3po case bb_8 case k_2so}

let type = StarWarsRobot.r2_d2 let type2: StarWarsRobot = .k_2so

func handleRobot(_ : StarWarsRobot) {}

handleRobot(.bb_8)

• An object type whose instances represent distinct predefined alternative values

Page 22: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

enum StarWarsRobot : Int{ case r2_d2 case c_3po case bb_8 case k_2so} func handleRobot(_ whichRobot: StarWarsRobot) {print(whichRobot)} //Enum element name printed

func handleRobot2(_ whichRobot: StarWarsRobot) {print(whichRobot.rawValue)} //Enum raw value printed (in this case an Int)

handleRobot(.bb_8) //prints bb_8 handleRobot2(.k_2so) //prints 3

• Can add an optional type declaration. Cases all then carry a fixed constant.

• If Int, values can be assigned but start at 0 by default.

• If String, values are string equivalents of case names

76

Enums

enum StarWarsRobot : Int{ case r2_d2 = 1 case c_3po case bb_8 case k_2so} func handleRobot(_ whichRobot: StarWarsRobot) {print(whichRobot)} //Enum element name printed

func handleRobot2(_ whichRobot: StarWarsRobot) {print(whichRobot.rawValue)} //Enum raw value printed (in this case an Int)

handleRobot(.bb_8) //prints bb_8 handleRobot2(.k_2so) //prints 4

Page 23: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

enum StarWarsRobot : String{ case r2_d2 = "R2-D2" case c_3po = "C-3PO" case bb_8 = "BB-8" case k_2so = "K-2SO"}

func handleRobot(_ whichRobot: StarWarsRobot) {print(whichRobot)}

func handleRobot2(_ whichRobot: StarWarsRobot) {print(whichRobot.rawValue)}

handleRobot(.bb_8) //prints bb_8handleRobot2(.k_2so) //prints K-2SO

let ourRobot = StarWarsRobot(rawValue:"R2-D2")

• Can assign values explicitly as part of the case declarations and use those raw values to map back to the associated case.

77

Enums

Page 24: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

78

Enums• Enums can have instance methods and static methods.

• You could always define a multi-state variable yourself, but Enums handle bounds checking automatically and are very readable in your code.

• Even values in your code that are 2-state may be better as Enums rather than Bool.

• One handy mapping is that the sections of an iOS segmented control start from 0 - so you could represent each option as a case in an Enum

enum audioClipOptions:Int { case start case stop case reset}

if selectedOption == audioClipOptions.start {}

Page 25: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

79

Protocols• Protocols are object types, but without protocol objects• A Protocol is not instantiated by your code• It is effectively a list of properties (without values) and methods

(with no code!)• Think of them as a named contract that you’ll conform to.• A “real” object type formally declares it belongs to a Protocol

type (aka adopting or conforming)• That object type must implement those properties and

methods itself.

Page 26: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

80

Protocols

• First example

• Note Protocol definition doesn’t include the body of the method.• We can add a comma-separated list of Protocols after the

superclass name.

protocol SomeProtocol { // protocol definition goes here func someFunc() // sample method}

// class adopting a protocol without a superclassclass MyClass : SomeProtocol { // Conforming to SomeProtocol func someFunc() { //we have to provide an implementation of the method }}

// class adopting a protocol with a superclassclass MyClass : Robot, SomeProtocol { // Conforming to SomeProtocol func someFunc() { //we have to provide an implementation of the method }}

Page 27: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

81

Protocols

• First example

• In the Protocol, property requirements are always declared as vars.• Protocol doesn't require that the property should be a stored one, or a

computed one. Only the name and type of the property.• Also specifies if property should be gettable or settable.

protocol SomeProtocol { //definition of the protocol var mustBeSettable: Int { get set } // read-write var doesNotNeedToBeSettable: Int { get } // read-only required func someFunc() }

// A class with a superclass, adopting a protocol class MyClass : Robot, SomeProtocol { var mustBeSettable: Int = 0 let doesNotNeedToBeSettable: Int init(theValue:Int){ doesNotNeedToBeSettable = theValue } // Conforming to SomeProtocol func someFunc() { //we have to provide an implementation of the method } }

Page 28: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

82

Protocols

• The FullyNamed protocol requires a conforming type to provide a fully-qualified name.

• The protocol doesn’t specify anything else about the nature of the conforming type— only that the type must provide a full name for itself.

• The protocol states that any FullyNamed type must have a gettable instance property called fullName, which is of type String.

protocol FullyNamed { var fullName: String { get } }

Page 29: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

83

Protocols protocol FullyNamed { var fullName: String { get } }

struct Person: FullyNamed { var fullName: String } let john = Person(fullName: "John Appleseed") // john.fullName is "John Appleseed"

Page 30: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

84

Protocols protocol FullyNamed { var fullName: String { get } }

class Starship: FullyNamed { var prefix: String? var name: String init(name: String, prefix: String? = nil) { self.name = name self.prefix = prefix } var fullName: String { return (prefix != nil ? prefix! + " " : "") + name }}var ncc1701 = Starship(name: "Enterprise", prefix: "USS")// ncc1701.fullName is "USS Enterprise"

Ternary conditional operator

Page 31: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

85

Aside: Ternary Conditional Operatorquestion ? answer1 : answer 2

class Starship: FullyNamed { var prefix: String? var name: String init(name: String, prefix: String? = nil) { self.name = name self.prefix = prefix } var fullName: String { return (prefix != nil ? prefix! + " " : "") + name }}var ncc1701 = Starship(name: "Enterprise", prefix: "USS")// ncc1701.fullName is "USS Enterprise"

Page 32: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

86

Protocols

• First example

• if get and set, then your property cannot be defined with let (a constant) or be a computed one.

• get only, is satisfied by let, var, etc. (and you are allowed, in your own code, to modify it)

protocol SomeProtocol { var mustBeSettable: Int { get set } // read-write var doesNotNeedToBeSettable: Int { get } // read-only required func someFunc()}

// protocol with superclassclass MyClass : Robot, SomeProtocol { var mustBeSettable: Int = 0 let doesNotNeedToBeSettable: Int init(theValue:Int){ doesNotNeedToBeSettable = theValue } // Conforming to SomeProtocol func someFunc() { //we have to provide an implementation of the method }}

Page 33: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

87

Protocols

• So what use are protocols?

• Good way to define a set of required functionality that other types can adopt.

• Also ensures that an adopting type has the features you require.

• By adopting some Apple standard protocols your class instances get some additional features / become better integrated with the O/S

• e.g. hashable

Page 34: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

88

Protocols struct GridPoint { /// A point in an x-y coordinate system. var x: Int var y: Int }

extension GridPoint: Hashable { var hashValue: Int { return x.hashValue ^ y.hashValue &* 16777619 //(x bitwise XOR y) overflow multiply by 16777619 } static func == (lhs: GridPoint, rhs: GridPoint) -> Bool { return lhs.x == rhs.x && lhs.y == rhs.y } }

var tappedPoints: Set = [GridPoint(x: 2, y: 3), GridPoint(x: 4, y: 1)] let nextTap = GridPoint(x: 0, y: 1) if tappedPoints.contains(nextTap) { print("Already tapped at (\(nextTap.x), \(nextTap.y)).") } else { tappedPoints.insert(nextTap) print("New tap detected at (\(nextTap.x), \(nextTap.y)).") }

extension GridPoint: Hashable {

}

in Swift 4.2

Page 35: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

89

Protocols

• First example

struct GridPoint { /// A point in an x-y coordinate system. var x: Int var y: Int}

extension GridPoint: Hashable {

}

var tappedPoints: Set = [GridPoint(x: 2, y: 3), GridPoint(x: 4, y: 1)]

print(tappedPoints)

[__lldb_expr_9.GridPoint(x: 4, y: 1), __lldb_expr_9.GridPoint(x: 2, y: 3)]

Page 36: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

90

Protocols

• First example

struct GridPoint { /// A point in an x-y coordinate system. var x: Int var y: Int}

extension GridPoint: Hashable {

}

var tappedPoints: Set = [GridPoint(x: 2, y: 3), GridPoint(x: 4, y: 1)]

print(tappedPoints)

[(4, 1), (2, 3)]

Page 37: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

91

Protocols

• First example

struct GridPoint { /// A point in an x-y coordinate system. var x: Int var y: Int }

extension GridPoint: Hashable, CustomStringConvertible { var description: String { return "(\(x), \(y))" } }

var tappedPoints: Set = [GridPoint(x: 2, y: 3), GridPoint(x: 4, y: 1)]

print(tappedPoints)

[(4, 1), (2, 3)]

Page 38: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

var users = ["phil", "boris", "terry", "valli", "irina"]

for (index, user) in users.enumerated() { users[index] = user.capitalized print(users[index])}//prints "Phil", "Boris", "Terry", "Valli", "Irina" - one per line

let searchName = "phil"if users[0] == searchName || users[0] == searchName.capitalized { print("Hey \(searchName), it's you!")}

• || is “or”, && is “and”• == is equality, != is inequality• = is an error (unless used in if let)

92

Other SwiftIf Statement logic

Page 39: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

Guard• Already seen that for optionals it may be necessary to test that a value

is not nil, using if let

• Nested if statements lead to the pyramid of doom if currentPlace != -1 { if places.count > currentPlace { if let name = places[currentPlace]["name"] { if let lat = places[currentPlace]["lat"] { if let lon = places[currentPlace]["lon"] { if let latitude = Double(lat) { if let longitude = Double(lon) { let span = MKCoordinateSpan(latitudeDelta: 0.008, longitudeDelta: 0.008) let coordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude) let region = MKCoordinateRegion(center: coordinate, span: span) self.map.setRegion(region, animated: true) let annotation = MKPointAnnotation() annotation.coordinate = coordinate annotation.title = name self.map.addAnnotation(annotation) } } } } } } }

if let name = places[currentPlace]["name"] {

93

Other Swift

Page 40: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

Guard

• One way to avoid this is to do your individual checks first, and for each one, exit if it fails

• But then this is testing for things you don’t want, which seems the wrong way round.

if currentPlace == -1 { return }//when we get here, currentPlace != -1

if places.count <= currentPlace { return }//when we get here, places.count > currentPlace //do the rest of our processing

if currentPlace != -1 { if places.count > currentPlace { . . . //do the rest of our processing

94

Other Swift

Page 41: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

95

Other SwiftGuard

• Guard lets you test for what you want, and handle the situation when it’s false

• Your code doesn’t end up massively indented and so it is easier to read.

guard currentPlace != -1 else { return } guard places.count > currentPlace else { return } . . . //do the rest of our processing

if currentPlace != -1 { if places.count > currentPlace { . . . //do the rest of our processing

Page 42: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

Guard• Nested if statements lead to the pyramid of doom

if currentPlace != -1 { if places.count > currentPlace { if let name = places[currentPlace]["name"] { if let lat = places[currentPlace]["lat"] { if let lon = places[currentPlace]["lon"] { if let latitude = Double(lat) { if let longitude = Double(lon) { let span = MKCoordinateSpan(latitudeDelta: 0.008, longitudeDelta: 0.008) let coordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude) let region = MKCoordinateRegion(center: coordinate, span: span) self.map.setRegion(region, animated: true) let annotation = MKPointAnnotation() annotation.coordinate = coordinate annotation.title = name self.map.addAnnotation(annotation) } } } } } } }

96

guard currentPlace != -1 else { return } guard places.count > currentPlace else { return } guard let name = places[currentPlace]["name"] else { return } guard let lat = places[currentPlace]["lat"] else { return } guard let lon = places[currentPlace]["lon"] else { return } guard let latitude = Double(lat) else { return } guard let longitude = Double(lon) else { return } let span = MKCoordinateSpan(latitudeDelta: 0.008, longitudeDelta: 0.008) let coordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude) let region = MKCoordinateRegion(center: coordinate, span: span) self.map.setRegion(region, animated: true) let annotation = MKPointAnnotation() annotation.coordinate = coordinate annotation.title = name self.map.addAnnotation(annotation)

Other Swift

Page 43: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

Guard• Normal rules of scope limit access to a variable/constant to the

scope in which it is declared e.g.

• However, using the guard equivalent, variable scope is extended to give access to the constant

if let name = places[currentPlace]["name"] { //the identifier "name" is valid here (of course) print(name) } //at this point, the identifier "name" is no longer valid

guard let name = places[currentPlace]["name"] else { return } let annotation = MKPointAnnotation() annotation.title = name //the identifier "name" is still valid here

97

Other Swift

Page 44: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

98

Method Syntax• Each method declaration consists of:

• the word func• a name (starting with a lowercase letter)• an optional list of arguments (and their data or object types)• an optional return type

• The syntax isfunc setNumerator(n: Int)-> Int

Return TypeDeclaring a method

(function)

Method Name Argument Type

Argument Name Indicates we return a value

Page 45: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

myInstance.method1()

myInstance.method2(name: argument)

myInstance.method3(anonymousArg1,name2: Arg2)

myInstance.method4(name1: arg1, name2: arg2)

99

Method Syntax

• A dot syntax is used

Object receiving the message (i.e. executing

the method)

The method nameThe main (first)

argument, usually named

Subsequent named arguments

arg-name : arg-value

method3 has been declared to not

have a named first parameter

Page 46: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

class Counter { var count: Int = 0 func incrementBy(amount: Int, numberOfTimes: Int) { count += amount * numberOfTimes } } let counter = Counter() //create an instance of the Counter class counter.incrementBy(amount: 5, numberOfTimes: 3) // counter value is now 15

100

Method Syntax• By default all parameters are named

class Counter { var count: Int = 0 func incrementBy(_ amount: Int, numberOfTimes: Int) { count += amount * numberOfTimes } } let counter = Counter() //create an instance of the Counter class counter.incrementBy(5, numberOfTimes: 3) // counter value is now 15

• Though can suppress a parameter name

Page 47: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

func greet(person: String, day: String) -> String { return "Hello \(person), today is \(day)." }

greet(person: ”Bob", day: "Tuesday")

101

Method Syntax

• By default, methods use their parameter names as labels for their arguments.

func greet(_ person: String, on day: String) -> String { return "Hello \(person), today is \(day)." }

greet("John", on: "Wednesday")

• Can create a custom argument label before the parameter name, or “_” to use no argument label.

Page 48: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

// Assume that we have a Person Class defined

var voter = Person() // Create a new instance of the class

voter.castVote() // call a no-parameter instance methodlet theAge = voter.age // Get something (getter)voter.age = 16 // Define something (setter)

if voter.canLegallyVote() {// allow the user to submit a ballot}

// Send several arguments to a methodvoter.registerForElection(ward:“Wirral West”,party:“Labour”)

// Embed the returning value of one message in anotherlet name = voter.spouse.name

102

Examples

Page 49: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

class Person { var name = "" ; var age = 0 //two statements on this one line - note the “;” var spouse: Person? = nil

func castVote() { //do the voting here } func canLegallyVote() -> Bool { return age >= 18 } func registerForElection(ward: String, party: String) { //do the registration stuff here } }

let voter = Person() // Create a new instance of the class var votersWife = Person() voter.name = "Terry" voter.age = 20 // Set the value of an instance property (setter) votersWife.name = "Valli" votersWife.age = 19 voter.spouse = votersWife votersWife.spouse = voter let theAge = voter.age // Get the value of an instance property (getter)

if voter.canLegallyVote() { // allow the user to submit a ballot print ("You \(voter.name), can vote") voter.castVote() // call a no-parameter instance method }

voter.registerForElection(ward:"Wirral West",party:"Labour") // Send 2 arguments to a method

if let name = voter.spouse?.name { print(name) } else { print("voter is not married") } 103

Page 50: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

104

Methods• Both Types and Instances can have methods/properties themselves (denoted

with the word static in a Type)• We’re used to seeing:

• The Double Type has a pi property: /// The mathematical constant pi. /// /// This value should be rounded toward zero to keep user computations with /// angles from inadvertently ending up in the wrong quadrant. A type that /// conforms to the `FloatingPoint` protocol provides the value for `pi` at /// its best possible precision. /// /// print(Double.pi) /// // Prints "3.14159265358979" public static var pi: Double { get }

let testString = "Just Testing!"

let theLength = testString.count

let zz = Double.pi

Page 51: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

105

Methods• The Double Type has the class method minimum

public static func minimum(_ x: Double, _ y: Double) -> Double

let x2 = Double.minimum(4.56, 8.92)In Swift 3, abs is a Class method for Double. In Swift 4

this has been deprecated, and abs()

is now global:

let x = abs(-3.75)

Page 52: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

class Robot {}

let R2D2 = Robot()

106

Method Syntax

• Now got an instance of the class Robot• An initialiser has been called (although it didn’t do very much).

class Robot { var name = “" //placeholder var serialNumber = 0 //placeholder init(name:String) { self.name = name } init(serialNumber:Int) { self.serialNumber = serialNumber } init(name:String, serialNumber:Int) { self.name = name self.serialNumber = serialNumber }} let myRobot = Robot(name:”R2-D2”)let yourRobot = Robot(name:"C3PO",serialNumber:935782342)

Page 53: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

107

Method Syntax• Now able to create an instance in any one of four ways.class Robot { var name = "" var serialNumber = 0 init() { } init(name:String) { self.name = name } init(serialNumber:Int) { self.serialNumber = serialNumber } init(name:String, serialNumber:Int) { self.name = name self.serialNumber = serialNumber }} let myRobot = Robot(name:”R2-D2”)let yourRobot = Robot(name:”C3PO",serialNumber:935782342) let herRobot = Robot(serialNumber:209)let hisRobot = Robot()

Page 54: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

108

Method Syntax

• Methods in Swift can have default values

• Can replace all four initialisers with one

class Robot { var name = "" var serialNumber = 0 init(name:String = "",serialNumber:Int = 0 ) { self.name = name self.serialNumber = serialNumber }}

let myRobot = Robot(name:”R2-D2")let yourRobot = Robot(name:”C3PO",serialNumber:935782342)let herRobot = Robot(serialNumber:209)let hisRobot = Robot()

Page 55: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

109

Method Syntax

• Don’t need to give properties values in their declarations, as long as they have values in all the initialisers!

class Robot { var name : String var serialNumber : Int init(name:String = "",serialNumber:Int = 0 ) { self.name = name self.serialNumber = serialNumber }}

let myRobot = Robot(name:"R2D2")let yourRobot = Robot(name:"C3PO",serialNumber:935782342)let herRobot = Robot(serialNumber:209)let hisRobot = Robot()

Page 56: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

110

Swift Basics

Apple have a good guide to Swift 5.1(from where some of these examples were borrowed):

https://docs.swift.org/swift-book/LanguageGuide/TheBasics.html

( Documentation now hosted by swift.org )

Page 57: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

111

Swift programs

• Xcode automatically generates the basic files for a project of the selected type.

• Typical single-view projects have:

Page 58: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

112

Swift programs

• AppDelegate.swift source file has 2 functions:• 1. Creates entry point and run loop for your app (equivalent

to “main” in C)• @UIApplicationMain creates an application object to

manage lifecycle of app and app delegate• 2. Defines the AppDelegate class - blueprint for the app

delegate object. Creates window where app content is drawn and provides place to respond to state transitions. You write your custom app-level code here.

Page 59: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

113

Swift programs• AppDelegate.swift

@UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate {

var window: UIWindow?

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { return true }

func applicationWillResignActive(_ application: UIApplication) { }

func applicationDidEnterBackground(_ application: UIApplication) { }

func applicationWillEnterForeground(_ application: UIApplication) { }

func applicationDidBecomeActive(_ application: UIApplication) { }

func applicationWillTerminate(_ application: UIApplication) { } }

import UIKit

@UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate {

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. return true }

// MARK: UISceneSession Lifecycle

func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { // Called when a new scene session is being created. // Use this method to select a configuration to create the new scene with. return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) }

func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) { // Called when the user discards a scene session. // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. // Use this method to release any resources that were specific to the discarded scenes, as they will not return. } }

Page 60: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

114

Swift programs• ViewController.swift (for single view apps)

import UIKit

class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. }

override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. }

}

• Your code to work with this view is placed here.• IBOutlets (labels etc.) and IBActions (buttons)• Class and Structure names start with A-Z• Method names start a-z

import UIKit class ViewController: UIViewController {

override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. }

} in Xcode 10

Page 61: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

Memory Management within Swift

Swift and the Foundation Framework

115

Page 62: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

116

Managing Memory

0

2

4

6

8

2007 2009 2012 2015 2017 2018

iPhone iMac

RAM configuration of the iMac and iPhone

Page 63: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

117

Managing Memory

• All Operating Systems support some sort of memory management - allocating and freeing up memory for processes

• Traditionally used some sort of Garbage Collection process to deal with formerly used blocks.

• Efficient Garbage Collection approaches have been problematic, and lead to Apple originally choosing manual memory management for iOS.

• In the tightly constrained environment of the iPhone, efficient use of memory is essential.

Page 64: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

118

Managing Memory• In Garbage Collection, an automated process runs at various

times, to check which blocks can be deallocated, and return them to the general pool.

• Typically this involves tracing objects that are reachable via a set of root objects (and disposing of those that aren’t reachable).

• This frees the user from too much worrying about memory allocation, but at a price.

• GC can be time-consuming and require significant extra resources - leading to other processes pausing.

• Not good if you’re in the middle of a phone call!

Page 65: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

119

Managing Memory

• Apple originally implemented a manual memory management model MRR - the user was responsible for indicating when blocks were no longer in use. These could then be handled at an appropriate point in the App lifecycle.

• In Objective C 2.0 (in 2007), Apple actually added a Garbage Collector for use on Mac OS Leopard. It was not enabled in Xcode projects by default, and eventually replaced by ARC.

Page 66: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

120

Managing Memory

• There are two approaches to managing memory used in iOS• ARC: Automatic Reference Counting • Introduced in iOS5 for Objective C. Standard in Swift• Compiler evaluates the requirements of your objects, and automatically inserts memory management calls at

compile time.

• MRR: Manual Retain-Release • Used prior to iOS5, but still available for Objective C• Developer explicitly inserts memory management calls (retain and release) into the code

• In Obj C, both approaches assume the developer will “allocate” new memory for new objects• Both approaches use retain counts for each object• However, ARC takes responsibility for retaining or releasing objects at compile time.

• In Swift, allocation and freeing of memory is automatic, via ARC

Page 67: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

121

Reference Counting in Memory Management

• Every allocated object has a retain count• Defined on NSObject (in the Foundation Framework)• As long as retain count is > 0, object is alive and valid

• When objects are shared (i.e. owned by more than one variable), then the retain count should track this.

• In Objective C:• +alloc and -copy create objects with retain count == 1• -retain increments retain count• -release decrements retain count

• When retain count reaches 0, object is destroyed• -dealloc method invoked automatically

Page 68: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

122

Object Graph

Class A

Heap

myThingalloc/init

Retain count = 1

Class B [myThing retain];

Retain count = 2

Heap

myThingClass A [myThing release];

Retain count = 1

Class B

Retain count = 0 ... object destroyed

[myThing release];

Page 69: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

123

ARC

• When you create an instance of a class, ARC also allocates a control block to maintain it

• When you are done with the instance, ARC frees up the memory it used

• But what if it deallocated an instance that actually was in use? - most probably your app would crash

• ARC tracks properties, constants and variables to check the instance is not being referenced

Page 70: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

124

ARCclass Person { let name: String init(name: String) { self.name = name print("\(name) is being initialized") } deinit { print("\(name) is being deinitialized") } }

var reference1: Person? var reference2: Person? var reference3: Person?

reference1 = Person(name: "Phil Jimmieson") // Prints "Phil Jimmieson is being initialized"

reference2 = reference1 reference3 = reference1

reference1 = nil reference2 = nil

reference3 = nil // Prints "Phil Jimmieson is being deinitialized"

Define a class “Person” that prints the name of the person when initialised /

deinitialised

Create 3 variables that will reference instances of the class

Create an instance of the class & assign to a variable

Assign that same instance to 2 other vars

Break these 2 strong references

Break final strong reference

Page 71: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

125

ARC

• It is possible to have a situation where an instance never has zero strong references.

• e.g. two class instances have a strong reference to each other.• known as a strong reference cycle• Can define relationships as weak or unowned to avoid this• Revisit our Person class example from earlier

Page 72: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

126

Examplesclass Person { var name = "" ; var age = 0 var spouse: Person? = nil init(name:String) { self.name = name; print("initialising \(name)") } deinit { print("deinitialising \(name)") } func castVote() { }//do the voting here func canLegallyVote() -> Bool { return age >= 18 } func registerForElection(ward: String, party: String) { }//do the registration stuff here } var voter: Person? //we’re setting up optionals to eventually reference instances of our class var votersWife: Person?

voter = Person(name: "Terry") votersWife = Person(name: "Valli") voter?.age = 20 votersWife?.age = 19 voter?.spouse = votersWife votersWife?.spouse = voter let theAge = voter?.age

if (voter?.canLegallyVote())! { // allow the user to submit a ballot print ("You \(voter!.name), can vote") voter?.castVote() }

voter?.registerForElection(ward:"Wirral West",party:"Labour")

if let name = voter?.spouse?.name { print(name) } else { print("voter is not married") }

voter = nil //terry is deinitialised at this point votersWife?.spouse = nil votersWife = nil //Valli is deinitialised here

Page 73: COMP228 [& 327] App Developmentcgi.csc.liv.ac.uk › ~phil › Teaching › COMP228 › lecturenotes...UIKit frameworks. • Provides a base layer of functionality for MacOS, iOS,

class Person { var name = "" ; var age = 0 weak var spouse: Person? = nil init(name:String) { self.name = name; print("initialising \(name)") } deinit { print("deinitialising \(name)") } func castVote() { }//do the voting here func canLegallyVote() -> Bool { return age >= 18 } func registerForElection(ward: String, party: String) { }//do the registration stuff here } var voter: Person? //we’re setting up optionals to eventually reference instances of our class var votersWife: Person?

voter = Person(name: "Terry") votersWife = Person(name: "Valli") voter?.age = 20 votersWife?.age = 19 voter?.spouse = votersWife votersWife?.spouse = voter let theAge = voter?.age

if (voter?.canLegallyVote())! { // allow the user to submit a ballot print ("You \(voter!.name), can vote") voter?.castVote() }

voter?.registerForElection(ward:"Wirral West",party:"Labour")

if let name = voter?.spouse?.name { print(name) } else { print("voter is not married") }

voter = nil //terry is deinitialised at this point //votersWife?.spouse = nil votersWife = nil //Valli is deinitialised here 127