2-01 Strings.key
Unit 2—Lesson 1:
Strings
Say
• Because Swift needs to be used for things that other languages are used for, we need a String type.
Strings
let greeting = “Hello”
var otherGreeting = “Salutations”
let joke = “””
Q: Why did the chicken cross the road?
A: To get to the other side!
“””
print(joke)
Q: Why did the chicken cross the road?
A: To get to the other side!
Say
• String instances can be created with the “” literal.
• let strings can’t be changed.
• var strings can be changed.
• Unicode is supported.
• If your string literal needs to be multiple lines, simply surround your set of characters with three double quotation marks
`”””`. In its multiline form, the string literal includes all of the lines between its opening and closing quotes. The string begins
on the first line after the opening quotes and ends on the line before the closing quotes.
Escaping
String basics
let greeting = “It is traditional in programming to print \”Hello, world!\””
Escape Description
\” Double quote
\\ Backslash
\t Tab
\r Carriage return (return to beginning of the next line)
Do
• Click to display the escape quotes.
Say
• If the string will include double quotes, you’ll need to use the backslash (\), known in Swift as the escape character.
Empty strings
String basics
var myString = “”
if myString.isEmpty {
print(“The string is empty”)
}
Characters
String basics
let a = “a” // ‘a’ is a string
let b: Character = “b” // ‘b’ is a Character
Say
• If you need a Character instance, you can still use “”, but you need to specify the Character type.
• Swift strings are not a collection of characters, but you can get the characters (someString.characters).
Do
• Show String under swiftdoc.org and point out the “extended grapheme clusters.”
• Explain that if you need all the details of how String is built and stored, you can find it.
Concatenation
let string1 = “Hello”
let string2 = “, world!”
var myString = string1 + string2 // “Hello, world!”
myString += ” Hello!” // “Hello, world! Hello!”
Say
• If you have two constant strings, you can use + to combine them into a new string.
• If you have a variable string, you can use += to append to it.
• As strings grow in complexity, the use of the + operator can make code tricky to handle. In the code above, for example,
you might forget to add a space before “Hello!”
Interpolation
let name = “Rick”
let age = 30
print(“\(name) is \(age) years old”)
Rick is 30 years old
Say
• You can insert the raw value of a constant or variable into a String by preceding the name with a backslash \ and wrapping
the name in parentheses ().
Expressions
Interpolation
let a = 4
let b = 5
print(“If a is \(a) and b is \(b), then a + b equals \(a+b)”)
If a is 4 and b is 5, then a + b equals 9
String equality and comparison
let month = “January”
let otherMonth = “January”
let lowercaseMonth = “january”
if month == otherMonth {
print(“They are the same”)
}
if month != lowercaseMonth {
print(“They are not the same.”)
}
They are the same.
They are not the same.
Ignoring case
String equality and comparison
let name = “Johnny Appleseed”
if name.lowercased() == “joHnnY aPPleseeD”.lowercased() {
print(“The two names are equal.”)
}
The two names are equal.
Say
• You can use the lowercased() method to normalize the two strings, comparing an all-lowercase version of the string with an
all-lowercase version of the calling string.
Prefix and suffix
String equality and comparison
let greeting = “Hello, world!”
print(greeting.hasPrefix(“Hello”))
print(greeting.hasSuffix(“world!”))
print(greeting.hasSuffix(“World!”))
true
true
false
Say
• Note that they are case sensitive.
Finding substrings
String equality and comparison
let greeting = “Hi Rick, my name is Amy.”
if greeting.contains(“my name is”) {
print(“Making an introduction”)
}
Making an introduction
Say
• Use the contains(_:) method to return a Boolean value that indicates whether or not the substring was found.
Checking length
String equality and comparison
let name = “Ryan Mears”
let count = name.count
let newPassword = “1234”
if newPassword.count < 8 {
print("This password is too short. Passwords should have at least 8 characters.")
}
This password is too short. Passwords should have at least 8 characters.
Say
• You can use the count property to determine the number of characters.
Using switch
String equality and comparison
let someCharacter: Character = "e"
switch someCharacter {
case "a", "e", "i", "o", "u":
print("\(someCharacter) is a vowel.")
default:
print("\(someCharacter) is not a vowel.")
}
e is a vowel.
Say
• You can use the switch statement to pattern-match multiple values of strings or characters and respond accordingly.
Unicode
let cow = "!"
let credentials = "résumé"
let myBook = "私の本"
print("∞".characters.count)
1
Say
• Note that the size of a string in bytes is not equal to the number of characters.
Lab: Strings
Unit 2—Lesson 1
Open and complete the exercises in Lab - Strings.playground
Unit 2—Lesson 2:
Functions
Say
• Because most programs don't just run linear code, we need functions.
Functions
tieMyShoes()
makeBreakfast(food: "scrambled eggs", drink: "orange juice")
Say
• tieMyShoes()—No parameters required; shoes are always tied the same way.
• makeBreakfast(food: ["eggs", "smoothie"])—Use parameters when you want to do the work differently at
different times.
Defining a function
Functions
func functionName (parameters) -> ReturnType {
// Body of the function
}
func displayPi() {
print(“3.1415926535”)
}
displayPi()
3.1415926535
Note
• This slide shows the syntax for defining a function.
• It also shows an implementation and call of a function with no arguments and no return.
Parameters
func triple(value: Int) {
let result = value * 3
print(“If you multiply \(value) by 3, you’ll get \(result).”)
}
triple(value: 10)
If you multiply 10 by 3, you’ll get 30.
Note
• This slide shows an implementation and call of function with a parameter.
Multiple parameters
Parameters
func multiply(firstNumber: Int, secondNumber: Int) {
let result = firstNumber * secondNumber
print(“The result is \(result).”)
}
multiply(firstNumber: 10, secondNumber: 5)
The result is 50.
Say
• This slide shows using more than one argument.
• Properly named arguments help document the function (“self-documenting code”).
• Note that named arguments must be passed in name order.
Return values
func multiply(firstNumber: Int, secondNumber: Int) -> Int {
let result = firstNumber * secondNumber
return result
}
Do
• Talk about functions returning a result.
• Click to highlight -> Int to show the return type.
• Click to highlight return result to show how the function returns the result.
Return values
func multiply(firstNumber: Int, secondNumber: Int) -> Int {
return firstNumber * secondNumber
}
let myResult = multiply(firstNumber: 10, secondNumber: 5)
print(“10 * 5 is \(myResult)”)
print(“10 * 5 is \(multiply(firstNumber: 10, secondNumber: 5))”)
Do
• Click to display capturing the return value, then printing it.
• Click again to display calling the function in String interpolation.
Argument labels
func sayHello(firstName: String) {
print(“Hello, \(firstName)!”)
}
sayHello(firstName: “Amy”)
Say
• Commonly use the same label internally and externally.
Argument labels
func sayHello(to: String, and: String) {
print(“Hello \(to) and \(and)”)
}
sayHello(to: “Luke”, and: “Dave”)
Say
• Sometimes having the same names inside and when calling isn’t so good.
External names
Argument labels
func sayHello(to person: String, and anotherPerson: String) {
print(“Hello \(person) and \(anotherPerson)”)
}
sayHello(to: “Luke”, and: “Dave”)
Say
• It may be better to have different descriptive names for calling and implementing.
Omitting labels
Argument labels
print(“Hello, world!”)
func add(_ firstNumber: Int, to secondNumber: Int) -> Int {
return firstNumber + secondNumber
}
let total = add(14, to: 6)
Say
• First is example of a function students have used that omitted the label.
• The second example defines a function that omits the label for the first parameter.
Default parameter values
func display(teamName: String, score: Int = 0) {
print(“\(teamName): \(score)”)
}
display(teamName: “Wombats”, score: 100)
display(teamName: “Wombats”)
Wombats: 100
Wombats: 0
Say
• Functions can have default values for parameters, and if so, you don’t need to pass them.
• Note that functions can have more than one parameter with a default value.
• This is a tricky language feature; go to the documentation to see the full function.
Lab: Functions
Unit 2—Lesson 2
Open and complete the exercises in Lab – Functions.playground
Unit 2—Lesson 3:
Structures
Note
• This is a long presentation.
• The recommendation is to stop partway through and ask students to complete a few of the lab exercises.
• Then resume the lecture, followed by students completing the exercises.
Structures
struct Person {
var name: String
}
Capitalize type names
Use lowercase for property names
Say
• Use the struct keyword.
• Note that because structs are value types, if you have a struct with var properties and an instance created into a let
variable, the properties aren’t changeable.
Accessing property values
Structures
struct Person {
var name: String
}
let person = Person(name: “Jasmine”)
print(person.name)
Jasmine
Say
• Use the dot syntax to access properties.
Adding functionality
Structures
struct Person {
var name: String
func sayHello() {
print(“Hello there! My name is \(name)!”)
}
}
let person = Person(name: “Jasmine”)
person.sayHello()
Hello there! My name is Jasmine!
Say
• Structures can have behavior.
• “Methods” are functions on a type.
Instances
struct Shirt {
var size: String
var color: String
}
let myShirt = Shirt(size: “XL”, color: “blue”)
let yourShirt = Shirt(size: “M”, color: “red”)
Note
• This slide shows creating two instances of a struct.
struct Car {
var make: String
var year: Int
var color: String
func startEngine() {…}
func drive() {…}
func park() {…}
func steer(direction: Direction) {…}
}
let firstCar = Car(make: “Honda”, year: 2010, color: “blue”)
let secondCar = Car(make: “Ford”, year: 2013, color: “black”)
firstCar.startEngine()
firstCar.drive()
Note
• This slide shows how to call methods on an instance: The firstCar has driven away, and the secondCar is still sitting there,
not running.
Initializers
let string = String.init() // “”
let integer = Int.init() // 0
let bool = Bool.init() // false
Say
• The standard library types all have init(), which returns an empty or default instance.
Initializers
var string = String() // “”
var integer = Int() // 0
var bool = Bool() // false
Say
• Whenever you’re using a new type, look at the inits. How can I get an instance?
Note
• This slide shows the () shortcut.
• Go to String in the docs and show the inits. They can all be run with or without the init. part.
Default values
Initializers
struct Odometer {
var count: Int = 0
}
let odometer = Odometer()
print(odometer.count)
0
Say
• For types we create: If all the stored properties of your struct have default values, the compiler writes the no-argument
initializer for you
• init() creates an instance with default values.
Note
• Some time during this part of the lesson, you should say that before initialization completes, all properties need a value.
Memberwise initializers
Initializers
let odometer = Odometer(count: 27000)
print(odometer.count)
27000
Say
• Structs always get a memberwise initializer from the compiler, whether or not you have default values.
• We saw that Odometer has a default value, but we can override that by calling the memberwise initializer.
Memberwise initializers
Initializers
struct Person {
var name: String
}
Say
• Person with a “name” property probably shouldn’t have a default var name: String (no default value, so no init() )
• So call the memberwise initializer.
Note
• The next slide builds upon this one.
Memberwise initializers
Initializers
struct Person {
var name: String
func sayHello() {
print(“Hello there!”)
}
}
let person = Person(name: “Jasmine”) // Memberwise initializer
struct Shirt {
let size: String
let color: String
}
let myShirt = Shirt(size: “XL”, color: “blue”) // Memberwise initializer
struct Car {
let make: String
let year: Int
let color: String
}
let firstCar = Car(make: “Honda”, year: 2010, color: “blue”) // Memberwise initializer
Note
• This slide shows two structs and their respective memberwise initializers.
Custom initializers
Initializers
struct Temperature {
var celsius: Double
}
let temperature = Temperature(celsius: 30.0)
let fahrenheitValue = 98.6
let celsiusValue = (fahrenheitValue – 32) / 1.8
let newTemperature = Temperature(celsius: celsiusValue)
Say
• In this example, the memberwise initializer requires you to calculate the CelsiusValue before you initialize a
newTemperature object.
Do
• Click to display using the Fahrenheit example.
Say
• What if we want to create one from a Fahrenheit value? We’d have to convert to Celsius in code and then pass that in.
struct Temperature {
var celsius: Double
init(celsius: Double) {
self.celsius = celsius
}
init(fahrenheit: Double) {
celsius = (fahrenheit – 32) / 1.8
}
}
let currentTemperature = Temperature(celsius: 18.5)
let boiling = Temperature(fahrenheit: 212.0)
print(currentTemperature.celsius)
print(boiling.celsius)
18.5
100.0
Say
• Instead of calculating Fahrenheit > Celsius outside the struct, make an initializer that takes a Fahrenheit value and converts
it for us.
• When we write our own initializers, we must make sure all properties are set to something before we’re done, so this one is
valid.
• Show String in the docs and point out the many init(…) methods.
• Note that as soon as we write ANY init methods, we no longer get:
– The init() that we get by having default values
– The memberwise initializer
Note
• If we write inits in an extension, we still get the compiler-written ones.
Lab: Structures
Unit 2—Lesson 3
Open and complete the following exercises in Lab –
Structures.playground:
•Exercise – Structs, Instances, and Default Values
•App Exercise – Workout Tracking
Instance methods
struct Size {
var width: Double
var height: Double
func area() -> Double {
return width * height
}
}
var someSize = Size(width: 10.0, height: 5.5)
let area = someSize.area() // Area is assigned a value of 55.0
Say
• The methods so far are “instance methods,” meant to be called on an instance.
• Calling area() will return different values depending on the width and height of the receiving instance.
Mutating methods
struct Odometer {
var count: Int = 0 // Assigns a default value to the ‘count’ property.
}
Need to
• Increment the mileage
•Reset the mileage
In the following example, a simple structure stores mileage data about a specific Car object. Before looking at the code,
consider what data the mileage counter needs to store and what actions it needs to perform.
1 Store the mileage count to be displayed on an odometer
2 Increment the mileage count to update the mileage when the car drives
3 Potentially reset the mileage count if the car drives beyond the number of miles that can be displayed on the
odometer
The last two require modifying the count property within the struct.
struct Odometer {
var count: Int = 0 // Assigns a default value to the ‘count’ property.
mutating func increment() {
count += 1
}
mutating func increment(by amount: Int) {
count += amount
}
mutating func reset() {
count = 0
}
}
var odometer = Odometer() // odometer.count defaults to 0
odometer.increment() // odometer.count is incremented to 1
odometer.increment(by: 15) // odometer.count is incremented to 16
odometer.reset() // odometer.count is reset to 0
Note
• Odometer type—Can have A and B trip odometers like a car does; each its own instance with its own count property
value.
• Note mutating—If a method on a value type changes a property, it must be annotated with mutating (another example of
Swift safety).
• Note that mutating isn’t required for Classes.
Computed properties
struct Temperature {
let celsius: Double
let fahrenheit: Double
let kelvin: Double
}
let temperature = Temperature(celsius: 0, fahrenheit: 32, kelvin: 273.15)
Say
• Let’s say we want to be able to get Celsius, Fahrenheit, and kelvin from a Temperature instance.
• Here’s a bad way to do it: properties for all three and a memberwise initializer.
• It’s bad because the caller has to calculate all three values to pass in.
struct Temperature {
var celsius: Double
var fahrenheit: Double
var kelvin: Double
init(celsius: Double) {
self.celsius = celsius
fahrenheit = celsius * 1.8 + 32
kelvin = celsius + 273.15
}
init(fahrenheit: Double) {
self.fahrenheit = fahrenheit
celsius = (fahrenheit – 32) / 1.8
kelvin = celsius + 273.15
}
init(kelvin: Double) {
self.kelvin = kelvin
celsius = kelvin – 273.15
fahrenheit = celsius * 1.8 + 32
}
}
let currentTemperature = Temperature(celsius: 18.5)
let boiling = Temperature(fahrenheit: 212.0)
let freezing = Temperature(kelvin: 273.15)
Say
• Another way would be an initializer for each scale of temperature.
• It’s better for the inits—only one value is needed.
• It’s still challenging for the state. Imagine that this thing can somehow do measurements itself; any time the temperature
changes, all three properties would need to be updated.
struct Temperature {
var celsius: Double
var fahrenheit: Double {
return celsius * 1.8 + 32
}
}
let currentTemperature = Temperature(celsius: 0.0)
print(currentTemperature.fahrenheit)
32.0
Say
• Computed properties would potentially simplify the state—have one Celsius property and compute the others.
• You would probably still want an init for each kind of temperature, but only one property for state.
Note
• Computed properties are “get” and optionally “set,” and if there’s only the getter you can omit the “get.”
• Computed properties must be “var.”
Add support for Kelvin
Challenge
Modify the following to allow the temperature to be read as Kelvin
struct Temperature {
let celsius: Double
var fahrenheit: Double {
return celsius * 1.8 + 32
}
}
Hint: Temperature in Kelvin is Celsius + 273.15
Do
• Add the kelvin-computed property as a demo or walkthrough:
var kelvin: Double {
return Celsius + 273.15
}
struct Temperature {
let celsius: Double
var fahrenheit: Double {
return celsius * 1.8 + 32
}
var kelvin: Double {
return celsius + 273.15
}
}
let currentTemperature = Temperature(celsius: 0.0)
print(currentTemperature.kelvin)
273.15
Note
• Here’s the solution for the challenge.
Property observers
struct StepCounter {
var totalSteps: Int = 0 {
willSet {
print(“About to set totalSteps to \(newValue)”)
}
didSet {
if totalSteps > oldValue {
print(“Added \(totalSteps – oldValue) steps”)
}
}
}
}
Say
• Swift allows you to observe any property and respond to the changes in the property’s value.
• willSet is an observer that defines a block of code that will be called before a property’s value is set.
You will have access to the new value that will be set to the property in a constant value named newValue.
• didSet defines a block of code that will be called after a property’s value has been set.
You will have access to the previous value of the property in a constant value named oldValue.
Property observers
var stepCounter = StepCounter()
stepCounter.totalSteps = 40
stepCounter.totalSteps = 100
About to set totalSteps to 40
Added 40 steps
About to set totalSteps to 100
Added 60 steps
Type properties and methods
struct Temperature {
static var boilingPoint = 100.0
static func convertedFromFahrenheit(_ temperatureInFahrenheit: Double) -> Double {
return(((temperatureInFahrenheit – 32) * 5) / 9)
}
}
let boilingPoint = Temperature.boilingPoint
let currentTemperature = Temperature.convertedFromFahrenheit(99)
let positiveNumber = abs(-4.14)
Say
• Use the static keyword on a property to make it “one per type.”
• Ask the type for the property.
• The naming convention is that types are capitalized and everything else is lowercase. This helps you see what’s going on.
Copying
var someSize = Size(width: 250, height: 1000)
var anotherSize = someSize
someSize.width = 500
print(someSize.width)
print(anotherSize.width)
500
250
Say
• Struct is a “value type”—copied on assignment when passed into a method or function and when returned from a function.
• This shows that if a struct is copied and then a change is made to the original, the copy doesn’t change.
Note
• This is conceptual—”copy on write” is really how it works. A copy isn’t made unless a property changes.
self
struct Car {
var color: Color
var description: String {
return “This is a \(self.color) car.”
}
}
Say
• “self” is the instance itself.
• This shows that “self.color” works to access properties.
When not required
self
Not required when property or method names exist on the current object
struct Car {
var color: Color
var description: String {
return “This is a \(color) car.”
}
}
When required
self
struct Temperature {
var celsius: Double
init(celsius: Double) {
self.celsius = celsius
}
}
Say
• In this example, the argument to init is the same as the property, so “self” is required to disambiguate.
Lab: Structures
Unit 2—Lesson 3
Open and complete the remaining exercises in
Lab – Structures.playground
Unit 2—Lesson 4:
Classes, Inheritance
Note
• Depending upon how long it takes for you to go through the early slides, you may want to break after about 15 minutes
and ask students to complete a few of the lab exercises.
• Then resume the lecture and complete the remaining exercises at the end.
Say
• We’re going to see that classes and structures are very similar.
• The main differences we’ll see in this lesson are inheritance, and value versus reference types.
class Person {
let name: String
init(name: String) {
self.name = name
}
func sayHello() {
print(“Hello there!”)
}
}
let person = Person(name: “Jasmine”)
print(person.name)
person.sayHello()
Jasmine
Hello there!
Say
• Use the class keyword to create a class
• In this example, that’s the only difference from a struct.
• As part of explanation for class, comparing it to struct, discuss how the capitalization indicates that “Person” is the class
or type and “person” is an instance.
Do
• Ask: “Why is self required in the init?”
• Answer: Because it’s ambiguous otherwise.
Inheritance
Base class
Subclass
Superclass
Vehicle
TandemBicycle
Bicycle
Say
• Use the class keyword to create a class
• In this example, that’s the only difference from a struct.
• As part of explanation for class, comparing it to struct, discuss how the capitalization indicates that “Person” is the class
or type and “person” is an instance.
Do
• Ask: “Why is self required in the init?”
• Answer: Because it’s ambiguous otherwise.
Defining a base class
Inheritance
class Vehicle {
var currentSpeed = 0.0
var description: String {
return “traveling at \(currentSpeed) miles per hour”
}
func makeNoise() {
// do nothing – an arbitrary vehicle doesn’t necessarily make a noise
}
}
let someVehicle = Vehicle()
print(“Vehicle: \(someVehicle.description)”)
Vehicle: traveling at 0.0 miles per hour
Note
• This slide shows a Vehicle class.
Create a subclass
Inheritance
class SomeSubclass: SomeSuperclass {
// subclass definition goes here
}
class Bicycle: Vehicle {
var hasBasket = false
}
Note
• This slide shows how to make a subclass.
• This slide shows Bicycle as subclass of Vehicle: Bicycle adds a hasBasket property.
Create a subclass
Inheritance
class Bicycle: Vehicle {
var hasBasket = false
}
let bicycle = Bicycle()
bicycle.hasBasket = true
bicycle.currentSpeed = 15.0
print(“Bicycle: \(bicycle.description)”)
Bicycle: traveling at 15.0 miles per hour
Note
• This slide shows how to:
– Make an instance of Bicycle
– Set a Vehicle property on bicycle (currentSpeed)
– Set a Bicycle property on bicycle (hasBasket)
Create a subclass
Inheritance
class Tandem: Bicycle {
var currentNumberOfPassengers = 0
}
Note
• This slide shows TandemBike as a subclass of Bicycle.
• Side note: Classes DO get an empty init() if the class has default values for all properties and you don’t write any other inits
(and the “write your extra inits in an extension and you still get the compiler-generated ones probably applies to classes).
• Side note: Classes get deinit. Value types don’t.
Create a subclass
Inheritance
class Tandem: Bicycle {
var currentNumberOfPassengers = 0
}
let tandem = Tandem()
tandem.hasBasket = true
tandem.currentNumberOfPassengers = 2
tandem.currentSpeed = 22.0
print(“Tandem: \(tandem.description)”)
Tandem: traveling at 22.0 miles per hour
Note
• This slide shows:
– How to make an instance of Tandem
– Setting properties of all levels of the hierarchy
Override methods and properties
Inheritance
class Train: Vehicle {
override func makeNoise() {
print(“Choo Choo!”)
}
}
let train = Train()
train.makeNoise()
Choo Choo!
Say
• This slide shows Train overriding makeNoise().
• The override keyword is required for Swift coding safety.
• You can immediately tell that code is overriding something.
• You can’t override something by mistake—the compiler will complain.
Override methods and properties
Inheritance
class Car: Vehicle {
var gear = 1
override var description: String {
return super.description + ” in gear \(gear)”
}
}
Say
• This slide shows Car overriding description.
• Properties can also be overridden with a getter.
Override methods and properties
Inheritance
class Car: Vehicle {
var gear = 1
override var description: String {
return super.description + ” in gear \(gear)”
}
}
let car = Car()
car.currentSpeed = 25.0
car.gear = 3
print(“Car: \(car.description)”)
Car: traveling at 25.0 miles per hour in gear 3
Note
• This slide shows using Car and calling description.
Override initializer
Inheritance
class Person {
let name: String
init(name: String) {
self.name = name
}
}
class Student: Person {
var favoriteSubject: String
}
Class ‘Student’ has no initializers!
Do
• Click to display the error.
Note
• The fix is on the next slide.
Override initializer
Inheritance
class Person {
let name: String
init(name: String) {
self.name = name
}
}
class Student: Person {
var favoriteSubject: String
init(name: String, favoriteSubject: String) {
self.favoriteSubject = favoriteSubject
super.init(name: name)
}
}
References
•When you create an instance of a class:
– Swift returns the address of that instance
– The returned address is assigned to the variable
•When you assign the address of an instance to multiple variables:
– Each variable contains the same address
– Update one instance, and all variables refer to the updated instance
class Person {
let name: String
var age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
}
var jack = Person(name: “Jack”, age: 24)
var myFriend = jack
jack.age += 1
print(jack.age)
print(myFriend.age)
25
25
Note
• This slide shows two references to the same instance of a Person class.
• It also shows that if you change a property, both references reflect that.
struct Person {
let name: String
var age: Int
}
var jack = Person(name: “Jack”, age: 24)
var myFriend = jack
jack.age += 1
print(jack.age)
print(myFriend.age)
25
24
Say
• This slide shows:
– The same code implemented as a Person struct
– That changing the value of a property of one instance doesn’t change the other instance
• That’s because myFriend is a copy of jack.
Memberwise initializers
•Swift does not create memberwise initializers for classes
•Common practice is for developers to create their own for their defined classes
Say
• Classes don’t get memberwise initializers.
• Classes DO get an empty init() if the class has default values for all properties and you don’t write any other inits.
Class or structure?
•Start new types as structures
•Use a class:
– When you’re working with a framework that uses classes
– When you want to refer to the same instance of a type in multiple places
– When you want to model inheritance
Lab: Classes.playground
Unit 2, Lesson 4
Open and complete the exercises in Lab – Classes.playground
Unit 2—Lesson 5:
Collections
Collection types
Array
Dictionary
Defining
Arrays
[value1, value2, value3]
var names: [String] = [“Anne”, “Gary”, “Keith”]
Note
• Shows the syntax: [value1, value2, value3, …].
Say
• True or false: Swift should be able to infer the “[String]” part.
• Answer: True (as shown on the next slide).
Defining
Arrays
[value1, value2, value3]
var names = [“Anne”, “Gary”, “Keith”]
Say
• The compiler can do type inference for collections, too.
Note
• Shows var names as type inferred to [String].
Defining
Arrays
var numbers = [1, -3, 50, 72, -95, 115]
Say
• The var numbers = [1, -3, 50] would be [Int].
• What if you want to restrict the array to Int8? Just specify it.
Defining
Arrays
var numbers: [Int8] = [1, -3, 50, 72, -95, 115]
contains
Arrays
let numbers = [4, 5, 6]
if numbers.contains(5) {
print(“There is a 5”)
}
There is a 5
Say
• someArray.contains(someInstance) returns true if true.
Note
• Contains uses == (the Equatable protocol).
Array types
var myArray: [Int] = []
var myArray: Array
var myArray = [Int]()
Note
• Shows the many ways to declare the type of things in an array.
repeating
Working with arrays
var myArray = [Int](repeating: 0, count: 100)
let count = myArray.count
if myArray.isEmpty { }
Note
• Shows the repeating Array initializer:
var myArray = [Int](repeating: 0, count: 100)
Creates an array filled with 100 zeros.
• Shows someArray.count (returns Int).
• Shows someArray.isEmpty (returns Bool).
Accessing or setting a specific item
Working with arrays
var names = [“Anne”, “Gary”, “Keith”]
let firstName = names[0]
print(firstName)
Anne
names[1] = “Paul”
print(names)
[“Anne”, “Paul”, “Keith”]
Say
• Change or retrieve a value by using array subscripting syntax which is similar to other languages.
Appending
Working with arrays
var names = [“Amy”]
names.append(“Joe”)
names += [“Keith”, “Jane”]
print(names)
[“Amy”, “Joe”, “Keith”, “Jane”]
Note
• Shows someArray.append(“object”).
• append() is limited to 1 item.
• append from array is: someArray.append(contentsOf: someOtherArray)
• Shows someArray += [“Keith”, “Jane”].
Inserting
Working with arrays
var names = [“Amy”, “Brad”, “Chelsea”, “Dan”]
names.insert(“Bob”, at: 0)
print(names)
[“Bob”, “Amy”, “Brad”, “Chelsea”, “Dan”]
Note
• Shows someArray.insert(“object” at: 0).
Say
• Note that there’s also someArray.insert(contentsOf: someOtherArray at: ).
Removing
Working with arrays
var names = [“Amy”, “Brad”, “Chelsea”, “Dan”]
let chelsea = names.remove(at:2)
let dan = names.removeLast()
print(names)
[“Amy”, “Brad”]
names.removeAll()
print(names)
[]
Say
• Note that remove(at:) returns the removed item.
Note
• There’s also removeFirst() and removeSubrange().
Working with arrays
var myNewArray = firstArray + secondArray
Arrays within arrays
Working with arrays
let array1 = [1,2,3]
let array2 = [4,5,6]
let containerArray = [array1, array2]
let firstArray = containerArray[0]
let firstElement = containerArray[0][0]
print(containerArray)
print(firstArray)
print(firstElement)
[[1, 2, 3], [4, 5, 6]]
[1, 2, 3]
1
Dictionaries
[key1 : value1, key2: value2, key3: value3]
var scores = [“Richard”: 500, “Luke”: 400, “Cheryl”: 800]
var myDictionary = [String: Int]()
var myDictionary = Dictionary
var myDictionary: [String: Int] = [:]
Note
Shows literal syntax and ways to instantiate.
Adding or modifying
Add/remove/modify a dictionary
var scores = [“Richard”: 500, “Luke”: 400, “Cheryl”: 800]
scores[“Oli”] = 399
let oldValue = scores.updateValue(100, forKey: “Richard”)
Say
• scores[“oli”] = 399 will update or insert a value for “oli”.
• scores.updateValue(100, forKey: “Richard”)
– Returns old value if there is one.
– Returns nil if not.
Adding or modifying
Add/remove/modify a dictionary
var scores = [“Richard”: 500, “Luke”: 400, “Cheryl”: 800]
scores[“Oli”] = 399
if let oldValue = scores.updateValue(100, forKey: “Richard”) {
print(“Richard’s old value was \(oldValue)”)
}
Richard’s old value was 500
Say
• Use if-let to run code only if a value was returned.
• If there wasn’t an existing value, the code with the brackets won’t be executed.
Removing
Add/remove/modify a dictionary
var scores = [“Richard”: 100, “Luke”: 400, “Cheryl”: 800]
scores[“Richard”] = nil
print(scores)
if let oldValue = scores.removeValue(forKey: “Luke”) {
print(“Luke’s score was \(oldValue) before he stopped playing”)
}
print(scores)
[“Cheryl”: 800, “Luke”: 400]
Luke’s score was 400 before he stopped playing
[“Cheryl”: 800]
Say
• scores[“oli”] = nil removes it if present.
scores.removeValue(forKey: “oli”)
• Returns old value if there is one.
• Returns nil if not.
Accessing a dictionary
var scores = [“Richard”: 500, “Luke”: 400, “Cheryl”: 800]
let players = Array(scores.keys) //[“Richard”, “Luke”, “Cheryl”]
let points = Array(scores.values) //[500, 400, 800]
if let myScore = scores[“Luke”] {
print(myScore)
}
400
if let henrysScore = scores[“Henry”] {
print(henrysScore)
}
Say
• What’s the return type?
• Answer: Int? because there may not be a key/value pair for the key.
Lab: Collections
Unit 2—Lesson 5
Open and complete the exercises in Lab – Collections.playground
Unit 2—Lesson 6:
Loops
Loops
for
while
Say
• Swift provides several different methods for looping.
• In this lesson we’ll focus on just two: for and while.
for loops
for index in 1…5 {
print(“This is number \(index)”)
}
Say
• “for” loops work with ranges—it has a nice, concise syntax:
for index in 1…5 {}
for loops
for _ in 1…5 {
print(“Hello!”)
}
Do
• Click to highlight the underscore “_”.
Say
• Use the underscore if you don’t need to use the index value.
for loops
let names = [“Joseph”, “Cathy”, “Winston”]
for name in names {
print(“Hello \(name)”)
}
for letter in “ABCDEFG”.characters {
print(“The letter is \(letter)”)
}
Do
• Click to highlight “names” as the range being iterated over.
Say
• This is often used to iterate over a collection.
Do
• Click again to highlight a string as a range of characters.
for loops
for (index, letter) in “ABCDEFG”.characters.enumerated() {
print(“\(index): \(letter)”)
}
Say
• enumerated() gives you the item and the index.
Note
• (index, letter) is a tuple.
for loops
let vehicles = [“unicycle” : 1, “bicycle” : 2, “tricycle” : 3, “quad bike” : 4]
for (vehicleName, wheelCount) in vehicles {
print(“A \(vehicleName) has \(wheelCount) wheels”)
}
Say
• Iterating over a Dictionary also gives you a tuple.
• It’s unordered because Dictionary is unordered.
while loops
var numberOfLives = 3
while numberOfLives > 0 {
playMove()
updateLivesCount()
}
Say
• Condition is at the top. The loop may happen zero times.
while loops
var numberOfLives = 3
while numberOfLives > 0 {
print(“I still have \(numberOfLives) lives.”)
}
Say
• The code inside the loop needs to eventually make the condition false.
while loops
var numberOfLives = 3
var stillAlive = true
while stillAlive {
print(“I still have \(numberOfLives) lives.”)
numberOfLives -= 1
if numberOfLives == 0 {
stillAlive = false
}
}
Control transfer statements
for counter in -10…10 {
print(counter)
if counter == 0 {
break
}
}
-10
-9
…
0
Note
• Shows that “break” exits a loop.
Lab: Loops
Unit 2—Lesson 6
Open and complete the exercises in Lab – Loops.playground.
© 2017 Apple Inc.
This work is licensed by Apple Inc. under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International license.
L550025C-en_WW App Development with Swift © 2017 Apple Inc. This work is licensed by Apple Inc. under the Creative Commons
Attribution-NonCommercial-ShareAlike 4.0 International license (https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode).
https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode