© 2014 Apple Inc. All rights reserved. Redistribution or public display not permitted without written permission from Apple.
#WWDC14
Intermediate Swift
Session 403
Brian Lanier Joe Groff
Developer Publications Engineer Swift Compiler Engineer
Tools
What You Will Learn
What You Will Learn
Optionals
What You Will Learn
Optionals
Memory management
What You Will Learn
Optionals
Memory management
Initialization
What You Will Learn
Optionals
Memory management
Initialization
Closures
What You Will Learn
Optionals
Memory management
Initialization
Closures
Pattern matching
Optionals
Brian Lanier
Developer Publications Engineer
String to Integer
> Enter your age:
>
!
!
!
_
String to Integer
> Enter your age:
>
!
!
!
_
let age = response.toInt()
String to Integer
> Enter your age:
>
!
let age = response.toInt()
!
String to Integer
> Enter your age:
>
!
let age = response.toInt()
!
34
String to Integer
> Enter your age:
>
!
let age = response.toInt()
!
String to Integer
> Enter your age:
>
!
let age = response.toInt()
!
thirty
String to Integer
> Enter your age:
>
!
let age = response.toInt()
!
String to Integer
> Enter your age:
>
!
let age = response.toInt()
!
wouldn't you like to know
> Enter your age:
>
!
let age = response.toInt()
String to Integer
> Enter your age:
>
!
let age = response.toInt()
String to Integer
how rude!
> Enter your age:
>
!
let age = response.toInt()
String to Integer
-1
NSNotFound
NULL
nil 0
INT_MAX
NSIntegerMax
Nil
how rude!
> Enter your age:
>
!
let age = response.toInt()
String to Integer
-1
NSNotFound
NULL
nil 0
INT_MAX
NSIntegerMax
Nil
?
how rude!
Optional Type
Optional Type
Represents possibly missing values
!
!
!
!
!
Optional Type
Represents possibly missing values
!
var optionalNumber: Int?
// default initialized to nil
!
!
!
6
Optional Type
Represents possibly missing values
!
var optionalNumber: Int?
// default initialized to nil
!
!
!
6
Optional Type
Represents possibly missing values
!
var optionalNumber: Int?
// default initialized to nil
!
optionalNumber = 6
!
! 6
Optional Type
Represents possibly missing values
!
var optionalNumber: Int?
// default initialized to nil
!
optionalNumber = 6
!
!
6
One Sentinel to Rule Them All
> Enter your age:
> thirty
!
let age = response.toInt()
// age: Int? = nil
Non-Optional Types
!
!
var myString: String = "Look, a real string!"
!
!
var myObject: MyClass = MyClass()
Non-Optional Types
Non-optional types can't be nil
!
var myString: String = nil
// compile-time error
!
var myObject: MyClass = nil
// compile-time error
Optional Return Types
func findIndexOfString(string: String, array: String[]) -> Int
!
!
!
!
!
}
{
Optional Return Types
func findIndexOfString(string: String, array: String[]) -> Int
!
!
!
!
!
}
? {
Optional Return Types
func findIndexOfString(string: String, array: String[]) -> Int? {
for (index, value) in enumerate(array) {
!
!
}
}
Optional Return Types
func findIndexOfString(string: String, array: String[]) -> Int? {
for (index, value) in enumerate(array) {
if value == string {
return index
}
}
}
Optional Return Types
func findIndexOfString(string: String, array: String[]) -> Int? {
for (index, value) in enumerate(array) {
if value == string {
return index
}
}
return nil
}
Unwrapping Optionals
var neighbors = ["Alex", "Anna", "Madison", "Dave"]
let index = findIndexOfString("Madison", neighbors)
!
var neighbors = ["Alex", "Anna", "Madison", "Dave"]
let index = findIndexOfString("Madison", neighbors)
!
if index {
println("Hello, (neighbors[index])")
} else {
println("Must've moved away")
}
Unwrapping Optionals
var neighbors = ["Alex", "Anna", "Madison", "Dave"]
let index: Int? = findIndexOfString("Madison", neighbors)
!
if index {
println("Hello, (neighbors[index])")
} else {
println("Must've moved away")
}
// error: value of optional type 'Int?' not unwrapped
Unwrapping Optionals
var neighbors = ["Alex", "Anna", "Madison", "Dave"]
let index = findIndexOfString("Madison", neighbors)
!
if index {
println("Hello, (neighbors[index!])")
} else {
println("Must've moved away")
}
Forced Unwrapping
var neighbors = ["Alex", "Anna", "Madison", "Dave"]
let index = findIndexOfString("Madison", neighbors)
!
if index {
println("Hello, (neighbors[index!])")
} else {
println("Must've moved away")
}
Forced Unwrapping
Hello, Madison
var neighbors = ["Alex", "Anna", "Madison", "Dave"]
let index = findIndexOfString("Reagan", neighbors)
!
!
println("Hello, (neighbors[index!])")
// runtime error!
Forced Unwrapping
Test and unwrap at the same time
!
var neighbors = ["Alex", "Anna", "Madison", "Dave"]
let index = findIndexOfString("Anna", neighbors)
!
Optional Binding
Test and unwrap at the same time
!
var neighbors = ["Alex", "Anna", "Madison", "Dave"]
let index = findIndexOfString("Anna", neighbors)
!
if let indexValue = index {
println("Hello, (neighbors[indexValue])")
} else {
println("Must've moved away")
}
Optional Binding
Test and unwrap at the same time
!
var neighbors = ["Alex", "Anna", "Madison", "Dave"]
let index = findIndexOfString("Anna", neighbors)
!
if let indexValue = index { // index is of type Int?
println("Hello, (neighbors[indexValue])")
} else {
println("Must've moved away")
}
Optional Binding
Test and unwrap at the same time
!
var neighbors = ["Alex", "Anna", "Madison", "Dave"]
let index = findIndexOfString("Anna", neighbors)
!
if let indexValue = index { // indexValue is of type Int
println("Hello, (neighbors[indexValue])")
} else {
println("Must've moved away")
}
Optional Binding
Test and unwrap at the same time
!
var neighbors = ["Alex", "Anna", "Madison", "Dave"]
let index = findIndexOfString("Anna", neighbors)
!
if let indexValue = index { // indexValue is of type Int
println("Hello, (neighbors[indexValue])")
} else {
println("Must've moved away")
}
Optional Binding
Test and unwrap at the same time
!
var neighbors = ["Alex", "Anna", "Madison", "Dave"]
!
!
if let index = findIndexOfString("Anna", neighbors) {
println("Hello, (neighbors[index])") // index is of type Int
} else {
println("Must've moved away")
}
Optional Binding
Test and unwrap at the same time
!
var neighbors = ["Alex", "Anna", "Madison", "Dave"]
!
!
if let index = findIndexOfString("Anna", neighbors) {
println("Hello, (neighbors[index])") // index is of type Int
} else {
println("Must've moved away")
}
Optional Binding
Hello, Anna
Optional Binding
class Person {
var residence: Residence?
}
!
Optional Binding
class Person {
var residence: Residence?
}
!
class Residence {
var address: Address?
}
!
Optional Binding
class Person {
var residence: Residence?
}
!
class Residence {
var address: Address?
}
!
class Address {
var buildingNumber: String?
var streetName: String?
var apartmentNumber: String?
}
Optional Binding
let paul = Person()
Person
residence: nil
Optional Binding
let paul = Person()
Person
residence:
Residence
address: nil
Optional Binding
let paul = Person()
Person
residence:
Residence
address:
Address
buildingNumber: nil
streetName: nil
apartmentNumber: nil
Optional Binding
let paul = Person()
Person
residence:
Residence
address:
Address
buildingNumber: "243"
streetName: "Main St."
apartmentNumber: nil
Optional Binding
var addressNumber: Int?
!
if let home = paul.residence {
!
!
!
!
!
!
}
Optional Binding
var addressNumber: Int?
!
if let home = paul.residence {
if let postalAddress = home.address {
!
!
!
!
}
}
Optional Binding
var addressNumber: Int?
!
if let home = paul.residence {
if let postalAddress = home.address {
if let building = postalAddress.buildingNumber {
!
!
}
}
}
Optional Binding
var addressNumber: Int?
!
if let home = paul.residence {
if let postalAddress = home.address {
if let building = postalAddress.buildingNumber {
if let convertedNumber = building.toInt() {
}
}
}
}
Optional Binding
var addressNumber: Int?
!
if let home = paul.residence {
if let postalAddress = home.address {
if let building = postalAddress.buildingNumber {
if let convertedNumber = building.toInt() {
addressNumber = convertedNumber
}
}
}
}
addressNumber = paul.residence?.address?.buildingNumber?.toInt()
Optional Chaining
addressNumber = paul.residence?.address?.buildingNumber?.toInt()
Optional Chaining
?
nil
Int
addressNumber = paul.residence?.address?.buildingNumber?.toInt()
Optional Chaining
? Int
nil
addressNumber = paul.residence?.address?.buildingNumber?.toInt()
Optional Chaining
? Int
nil
addressNumber = paul.residence?.address?.buildingNumber?.toInt()
Optional Chaining
?
nil
Int
Optional Chaining
?
addressNumber = paul.residence?.address?.buildingNumber?.toInt()
nil
Int
Optional Chaining
?
addressNumber = paul.residence?.address?.buildingNumber?.toInt()
nil
Int
Optional Chaining
?
addressNumber = paul.residence?.address?.buildingNumber?.toInt()
nil
Int
Optional Chaining
?
addressNumber = paul.residence?.address?.buildingNumber?.toInt()
nil
Int
Optional Chaining
addressNumber = paul.residence?.address?.buildingNumber?.toInt()
?
nil
Int
Optional Chaining
addressNumber = paul.residence?.address?.buildingNumber?.toInt()
?
nil
Int
Optional Chaining
?
addressNumber = paul.residence?.address?.buildingNumber?.toInt()
nil
Int
Optional Chaining
?
addressNumber = paul.residence?.address?.buildingNumber?.toInt()
nil
Int
Optional Chaining
?
addressNumber = paul.residence?.address?.buildingNumber?.toInt()
nil
Int
Optional Chaining
?
addressNumber = paul.residence?.address?.buildingNumber?.toInt()
nil
Int
Optional Chaining
?
addressNumber = paul.residence?.address?.buildingNumber?.toInt()
nil
Int
Optional Chaining
?
addressNumber = paul.residence?.address?.buildingNumber?.toInt()
nil
Int
Optional Chaining
?
addressNumber = paul.residence?.address?.buildingNumber?.toInt()
nil
Int
Optional Chaining
?
addressNumber = paul.residence?.address?.buildingNumber?.toInt()
nil
Int
Optional Chaining
?
addressNumber = paul.residence?.address?.buildingNumber?.toInt()
"243"
nil
Int
Optional Chaining
?
addressNumber = paul.residence?.address?.buildingNumber?.toInt()
243
nil
Int
Int
Optional Chaining
addressNumber = paul.residence?.address?.buildingNumber?.toInt()
nil
?
Int
Optional Chaining
addressNumber = paul.residence?.address?.buildingNumber?.toInt()
nil
?
Optional Chaining
243
addressNumber = paul.residence?.address?.buildingNumber?.toInt()
Optional Chaining
Combine with optional binding to unwrap
!
Optional Chaining
Combine with optional binding to unwrap
!
if let addressNumber = paul.residence?.address?.buildingNumber?.toInt() {
addToDatabase("Paul", addressNumber)
}
enum Optional<T> {
case None
case Some(T)
}
Optionals Under the Hood
• Advanced Swift Presidio Thursday 11:30PM
Optionals
Optionals
Use optionals to safely work with possibly missing values
• Missing values are nil
• Present values are wrapped in an optional
Optionals
Use optionals to safely work with possibly missing values
• Missing values are nil
• Present values are wrapped in an optional
Unwrap an optional to access its underlying value
• Use the forced-unwrapping operator (!) only if you are sure
• Use if let optional binding to test and unwrap at the same time
Optionals
Use optionals to safely work with possibly missing values
• Missing values are nil
• Present values are wrapped in an optional
Unwrap an optional to access its underlying value
• Use the forced-unwrapping operator (!) only if you are sure
• Use if let optional binding to test and unwrap at the same time
Optional chaining (?) is a concise way to work with chained optionals
Memory Management
Joe Groff
Swift Compiler Engineer
Automatic Reference Counting
Automatic Reference Counting
class BowlingPin {}
func juggle(count: Int) {
var left = BowlingPin()
Automatic Reference Counting
class BowlingPin {}
func juggle(count: Int) {
var left = BowlingPin()
BowlingPin
Automatic Reference Counting
class BowlingPin {}
func juggle(count: Int) {
var left = BowlingPin()
BowlingPin
left
Automatic Reference Counting
class BowlingPin {}
func juggle(count: Int) {
var left = BowlingPin()
if count > 1 {
var right = BowlingPin()
BowlingPin
left
BowlingPin
right
Automatic Reference Counting
class BowlingPin {}
func juggle(count: Int) {
var left = BowlingPin()
if count > 1 {
var right = BowlingPin()
right = left
BowlingPin
left right
Automatic Reference Counting
class BowlingPin {}
func juggle(count: Int) {
var left = BowlingPin()
if count > 1 {
var right = BowlingPin()
right = left
} // right goes out of scope
BowlingPin
left
Automatic Reference Counting
class BowlingPin {}
func juggle(count: Int) {
var left = BowlingPin()
if count > 1 {
var right = BowlingPin()
right = left
} // right goes out of scope
BowlingPin
left
Automatic Reference Counting
class BowlingPin {}
func juggle(count: Int) {
var left = BowlingPin()
if count > 1 {
var right = BowlingPin()
right = left
} // right goes out of scope
} // left goes out of scope
Ownership
Ownership
class Apartment {
var tenant: Person?
}
Ownership
class Apartment {
var tenant: Person?
}
class Person {
var home: Apartment?
Ownership
class Apartment {
var tenant: Person?
}
class Person {
var home: Apartment?
func moveIn(apt: Apartment) {
self.home = apt
apt.tenant = self
}
}
Ownership
Ownership
var renters = ["Elsvette": Person()]
Person
renters
Ownership
var renters = ["Elsvette": Person()]
var apts = [507: Apartment()]
Person
renters
Apartment
apts
Ownership
var renters = ["Elsvette": Person()]
var apts = [507: Apartment()]
renters["Elsvette"]!.moveIn(apts[507]!)
Person
renters
Apartment
apts
home tenant
Ownership
var renters = ["Elsvette": Person()]
var apts = [507: Apartment()]
renters["Elsvette"]!.moveIn(apts[507]!)
renters["Elsvette"] = nil
Person Apartment
apts
home tenant
Ownership
var renters = ["Elsvette": Person()]
var apts = [507: Apartment()]
renters["Elsvette"]!.moveIn(apts[507]!)
renters["Elsvette"] = nil
Person Apartment
apts
home tenant
Ownership
var renters = ["Elsvette": Person()]
var apts = [507: Apartment()]
renters["Elsvette"]!.moveIn(apts[507]!)
renters["Elsvette"] = nil
apts[507] = nil
Person Apartment
home tenant
Ownership
var renters = ["Elsvette": Person()]
var apts = [507: Apartment()]
renters["Elsvette"]!.moveIn(apts[507]!)
renters["Elsvette"] = nil
apts[507] = nil
Person Apartment
home tenant
Weak References
class Apartment {
!
}
class Person {
!
!
func moveIn(apt: Apartment) {
self.home = apt
apt.tenant = self
}
}
var tenant: Person?
var home: Apartment?
Weak References
class Apartment {
!
}
class Person {
!
!
func moveIn(apt: Apartment) {
self.home = apt
apt.tenant = self
}
}
var tenant: Person?weak
var home: Apartment?weak
Weak References
Person
renters
Apartment
apts
Weak References
var renters = ["Elsvette": Person()]
var apts = [507: Apartment()]
Person
renters
Apartment
apts
Weak References
var renters = ["Elsvette": Person()]
var apts = [507: Apartment()]
renters["Elsvette"]!.moveIn(apts[507]!)
Person
renters
Apartment
apts
home tenant
Weak References
var renters = ["Elsvette": Person()]
var apts = [507: Apartment()]
renters["Elsvette"]!.moveIn(apts[507]!)
renters["Elsvette"] = nil
Person Apartment
apts
home tenant
Weak References
var renters = ["Elsvette": Person()]
var apts = [507: Apartment()]
renters["Elsvette"]!.moveIn(apts[507]!)
renters["Elsvette"] = nil
Apartment
apts
tenant
Weak References
var renters = ["Elsvette": Person()]
var apts = [507: Apartment()]
renters["Elsvette"]!.moveIn(apts[507]!)
renters["Elsvette"] = nil
Apartment
apts
Weak References
var renters = ["Elsvette": Person()]
var apts = [507: Apartment()]
renters["Elsvette"]!.moveIn(apts[507]!)
renters["Elsvette"] = nil
apts[507] = nil
Using Weak References
Using Weak References
Weak references are optional values
Using Weak References
Weak references are optional values
Binding the optional produces a strong reference
if let tenant = apt.tenant {
tenant.buzzIn()
}
Using Weak References
Weak references are optional values
Binding the optional produces a strong reference
if let tenant = apt.tenant {
tenant.buzzIn()
}
apt.tenant?.buzzIn()
Using Weak References
Using Weak References
Testing a weak reference alone does not produce a strong reference
if apt.tenant {
apt.tenant!.cashRentCheck()
apt.tenant!.greet()
}
Using Weak References
Testing a weak reference alone does not produce a strong reference
Chaining doesn't preserve a strong reference between method invocations
if apt.tenant {
apt.tenant!.cashRentCheck()
apt.tenant!.greet()
}
apt.tenant?.cashRentCheck()
apt.tenant?.greet()
Same-Lifetime Relationships
Same-Lifetime Relationships
class Person {
var card: CreditCard?
}
Same-Lifetime Relationships
class Person {
var card: CreditCard?
}
class CreditCard {
holder: Personlet
Same-Lifetime Relationships
class Person {
var card: CreditCard?
}
class CreditCard {
holder: Personlet
Same-Lifetime Relationships
class Person {
var card: CreditCard?
}
class CreditCard {
holder: Person
init(holder: Person) {
self.holder = holder
}
}
let
Same-Lifetime Relationships
class Person {
var card: CreditCard?
}
class CreditCard {
!
!
init(holder: Person) {
self.holder = holder
}
}
let holder: Person
Same-Lifetime Relationships
class Person {
var card: CreditCard?
}
class CreditCard {
!
!
init(holder: Person) {
self.holder = holder
}
}
letweak holder: Person
Same-Lifetime Relationships
class Person {
var card: CreditCard?
}
class CreditCard {
!
!
init(holder: Person) {
self.holder = holder
}
}
letweak holder: Person?
Same-Lifetime Relationships
class Person {
var card: CreditCard?
}
class CreditCard {
!
!
init(holder: Person) {
self.holder = holder
}
}
weak holder: Personvar ?
Unowned References
class Person {
var card: CreditCard?
}
class CreditCard {
!
!
init(holder: Person) {
self.holder = holder
}
}
holder: Personlet
Unowned References
class Person {
var card: CreditCard?
}
class CreditCard {
!
!
init(holder: Person) {
self.holder = holder
}
}
holder: Personletunowned
Unowned References
Unowned References
var renters = ["Elsvette": Person()]
Person
renters
Unowned References
var renters = ["Elsvette": Person()]
customers["Elsvette"]!.saveCard()
Person
renters
card
CreditCard
holder
Unowned References
var renters = ["Elsvette": Person()]
customers["Elsvette"]!.saveCard()
customers["Elsvette"] = nil
Person
card
CreditCard
holder
Unowned References
var renters = ["Elsvette": Person()]
customers["Elsvette"]!.saveCard()
customers["Elsvette"] = nil
Using Unowned References
Using Unowned References
let holder = card.holder
Using Unowned References
let holder = card.holder
card.holder.charge(2.19)
Strong, Weak, and Unowned References
Use strong references from owners to the objects they own
Strong, Weak, and Unowned References
Strong, Weak, and Unowned References
Strong, Weak, and Unowned References
Use weak references among objects with independent lifetimes
Strong, Weak, and Unowned References
Use weak references among objects with independent lifetimes
Strong, Weak, and Unowned References
Use weak references among objects with independent lifetimes
Strong, Weak, and Unowned References
Strong, Weak, and Unowned References
Use unowned references from owned objects with the same lifetime
Strong, Weak, and Unowned References
Use unowned references from owned objects with the same lifetime
Strong, Weak, and Unowned References
Use unowned references from owned objects with the same lifetime
Memory Management
Automatic, safe, predictable
Think about relationships between objects
Model ownership using strong, weak, and unowned references
Initialization
Brian Lanier
Developer Publications Engineer
!
!
Every value must be initialized before it is used
!
!
Every value must be initialized before it is used
Initialization
var message: String
!
Initialization
var message: String
!
if sessionStarted {
message = "Welcome to Intermediate Swift!"
}
!
println(message)
Initialization
var message: String
!
if sessionStarted {
message = "Welcome to Intermediate Swift!"
}
!
println(message)
// error: variable 'message' used before being initialized
Initialization
var message: String
!
if sessionStarted {
message = "Welcome to Intermediate Swift!"
} else {
message = "See you next year!"
}
!
println(message)
Initialization
var message: String
!
if sessionStarted {
message = "Welcome to Intermediate Swift!"
} else {
message = "See you next year!"
}
!
println(message)
Welcome to Intermediate Swift!
Initializers
Initializers
Initializers handle the responsibility of fully initializing an instance
Initializers
Initializers handle the responsibility of fully initializing an instance
!
init() {…}
!
Initializers
Initializers handle the responsibility of fully initializing an instance
!
init() {…}
!
let instance = MyClass()
Initializers
Initializers handle the responsibility of fully initializing an instance
!
init(
!
let instance = MyClass(
) {…}
)
Initializers
Initializers handle the responsibility of fully initializing an instance
!
init(
!
let instance = MyClass(
luckyNumber: Int, message: String ) {…}
)
Initializers
Initializers handle the responsibility of fully initializing an instance
!
init(
!
let instance = MyClass(
luckyNumber: Int, message: String
luckyNumber: 42, message: "Not today"
) {…}
)
Structure Initialization
Structure Initialization
struct Color {
let red, green, blue: Double
}
Structure Initialization
struct Color {
let red, green, blue: Double
init(grayScale: Double) {
red = grayScale
green = grayScale
blue = grayScale
}
}
Structure Initialization
struct Color {
let red, green, blue: Double
init(grayScale: Double) {
red = grayScale
green = grayScale
blue = grayScale
}
}
Structure Initialization
struct Color {
let red, green, blue: Double
init(grayScale: Double) {
green = grayScale
blue = grayScale
}
}
// error: variable 'self.red' used before being initialized
Structure Initialization
struct Color {
let red, green, blue: Double
mutating func validateColor() { ... }
init(grayScale: Double) {
red = grayScale
green = grayScale
validateColor()
blue = grayScale
}
}
Structure Initialization
struct Color {
let red, green, blue: Double
mutating func validateColor() { ... }
init(grayScale: Double) {
red = grayScale
green = grayScale
validateColor()
blue = grayScale
}
}
validateColor()
struct Color {
let red, green, blue: Double
mutating func validateColor() { ... }
init(grayScale: Double) {
red = grayScale
green = grayScale
blue = grayScale
}
}
// error: 'self' used before being initialized
Structure Initialization
validateColor()
struct Color {
let red, green, blue: Double
mutating func validateColor() { ... }
init(grayScale: Double) {
red = grayScale
green = grayScale
blue = grayScale
}
}
// error: 'self' used before being initialized
self.
Structure Initialization
Structure Initialization
struct Color {
let red, green, blue: Double
mutating func validateColor() { ... }
init(grayScale: Double) {
red = grayScale
green = grayScale
blue = grayScale
validateColor()
}
}
Memberwise Initializers
struct Color {
let red, green, blue: Double
}
Memberwise Initializers
struct Color {
let red, green, blue: Double
}
!
!
let magenta = Color(red: 1.0, green: 0.0, blue: 1.0)
Default Values
struct Color {
let red = 0.0, green = 0.0, blue = 0.0
}
Default Initializer
struct Color {
let red = 0.0, green = 0.0, blue = 0.0
}
!
let black = Color()
Class Initialization
Class Initialization
class Car {
var paintColor: Color
init(color: Color) {
paintColor = color
}
}
Class Initialization
class Car {
var paintColor: Color
init(color: Color) {
paintColor = color
}
}
Class Initialization
class Car {
var paintColor: Color
init(color: Color) {
paintColor = color
}
}
!
class RaceCar: Car {
var hasTurbo: Bool
!
init(color: Color, turbo: Bool) {
hasTurbo = turbo
super.init(color: color)
}
}
Class Initialization
class Car {
var paintColor: Color
init(color: Color) {
paintColor = color
}
}
!
class RaceCar: Car {
var hasTurbo: Bool
!
init(color: Color, turbo: Bool) {
hasTurbo = turbo
super.init(color: color)
}
}
Class Initialization
class Car {
var paintColor: Color
init(color: Color) {
paintColor = color
}
}
!
class RaceCar: Car {
var hasTurbo: Bool
!
init(color: Color, turbo: Bool) {
hasTurbo = turbo
super.init(color: color)
}
}
Class Initialization
class Car {
var paintColor: Color
init(color: Color) {
paintColor = color
}
}
!
class RaceCar: Car {
var hasTurbo: Bool
!
init(color: Color, turbo: Bool) {
hasTurbo = turbo
super.init(color: color)
}
}
Class Initialization
class Car {
var paintColor: Color
init(color: Color) {
paintColor = color
}
}
!
class RaceCar: Car {
var hasTurbo: Bool
!
init(color: Color, turbo: Bool) {
hasTurbo = turbo
super.init(color: color)
}
}
Class Initialization
class Car {
var paintColor: Color
init(color: Color) {
paintColor = color
!
class RaceCar: Car {
var hasTurbo: Bool
!
init(color: Color, turbo: Bool) {
hasTurbo = turbo
super.init(color: color)
}
}
}
}
Class Initialization
class Car {
var paintColor: Color
init(color: Color) {
paintColor = color
!
class RaceCar: Car {
var hasTurbo: Bool
!
init(color: Color, turbo: Bool) {
hasTurbo = turbo
super.init(color: color)
}
}
}
}
Class Initialization
class Car {
var paintColor: Color
init(color: Color) {
paintColor = color
!
class RaceCar: Car {
var hasTurbo: Bool
!
init(color: Color, turbo: Bool) {
super.init(color: color)
hasTurbo = turbo
}
}
}
}
Class Initialization
class Car {
var paintColor: Color
init(color: Color) {
paintColor = color
}
}
!
class RaceCar: Car {
var hasTurbo: Bool
!
init(color: Color, turbo: Bool) {
super.init(color: color)
hasTurbo = turbo
}
}
Class Initialization
class Car {
var paintColor: Color
func fillGasTank() {...}
init(color: Color) {
paintColor = color
fillGasTank()
}
}
!
class RaceCar: Car {
var hasTurbo: Bool
override func fillGasTank() { ... }
init(color: Color, turbo: Bool) {
super.init(color: color)
hasTurbo = turbo
}
}
Class Initialization
class Car {
var paintColor: Color
func fillGasTank() {...}
init(color: Color) {
paintColor = color
fillGasTank()
}
}
!
class RaceCar: Car {
var hasTurbo: Bool
override func fillGasTank() { ... }
init(color: Color, turbo: Bool) {
super.init(color: color)
hasTurbo = turbo
}
}
Class Initialization
class Car {
var paintColor: Color
func fillGasTank() {...}
init(color: Color) {
paintColor = color
fillGasTank()
}
}
!
class RaceCar: Car {
var hasTurbo: Bool
override func fillGasTank() { ... }
init(color: Color, turbo: Bool) {
super.init(color: color)
hasTurbo = turbo
}
}
Class Initialization
class Car {
var paintColor: Color
func fillGasTank() {...}
init(color: Color) {
paintColor = color
fillGasTank()
}
}
!
class RaceCar: Car {
var hasTurbo: Bool
override func fillGasTank() { ... }
init(color: Color, turbo: Bool) {
super.init(color: color)
hasTurbo = turbo
}
}
Class Initialization
class Car {
var paintColor: Color
func fillGasTank() {...}
init(color: Color) {
paintColor = color
fillGasTank()
}
}
!
class RaceCar: Car {
var hasTurbo: Bool
override func fillGasTank() { ... }
init(color: Color, turbo: Bool) {
super.init(color: color)
hasTurbo = turbo
}
}
Class Initialization
class Car {
var paintColor: Color
func fillGasTank() {...}
init(color: Color) {
paintColor = color
fillGasTank()
}
}
!
class RaceCar: Car {
var hasTurbo: Bool
override func fillGasTank() { ... }
init(color: Color, turbo: Bool) {
super.init(color: color)
hasTurbo = turbo
}
}
Class Initialization
class Car {
var paintColor: Color
func fillGasTank() {...}
init(color: Color) {
paintColor = color
fillGasTank()
!
class RaceCar: Car {
var hasTurbo: Bool
override func fillGasTank() { ... }
init(color: Color, turbo: Bool) {
super.init(color: color)
hasTurbo = turbo
Class Initialization
class Car {
var paintColor: Color
func fillGasTank() {...}
init(color: Color) {
paintColor = color
fillGasTank()
}
}
!
class RaceCar: Car {
var hasTurbo: Bool
override func fillGasTank() { ... }
init(color: Color, turbo: Bool) {
super.init(color: color)
hasTurbo = turbo
}
} // error: property 'hasTurbo' not initialized at super.init call
Class Initialization
class Car {
var paintColor: Color
func fillGasTank() {...}
init(color: Color) {
paintColor = color
fillGasTank()
}
}
!
class RaceCar: Car {
var hasTurbo: Bool
override func fillGasTank() { ... }
init(color: Color, turbo: Bool) {
hasTurbo = turbo
super.init(color: color)
}
}
super.init(color: color)
hasTurbo = turbo
Class Initialization
class Car {
var paintColor: Color
func fillGasTank() {...}
init(color: Color) {
paintColor = color
fillGasTank()
}
}
!
class RaceCar: Car {
var hasTurbo: Bool
override func fillGasTank() { ... }
init(color: Color, turbo: Bool) {
hasTurbo = turbo
super.init(color: color)
}
}
super.init(color: color)
hasTurbo = turbo
Initializer Delegation
BaseClass
SuperClass
Class
Initializer Delegation
BaseClass
SuperClass
Class
Designated
Designated
Designated Designated
Initializer Delegation
BaseClass
SuperClass
Class
Designated
Designated
Designated Designated
Convenience Convenience
Convenience Convenience
Convenience
Convenience Initializers
class RaceCar: Car {
var hasTurbo: Bool
init(color: Color, turbo: Bool) {
hasTurbo = turbo
super.init(color: color)
}
!
!
!
!
!
!
!
}
Convenience Initializers
class RaceCar: Car {
var hasTurbo: Bool
init(color: Color, turbo: Bool) {
hasTurbo = turbo
super.init(color: color)
}
!
init(color: Color) {
self.init(color: color, turbo: true)
}
!
!
!
}
Convenience Initializers
class RaceCar: Car {
var hasTurbo: Bool
init(color: Color, turbo: Bool) {
hasTurbo = turbo
super.init(color: color)
}
!
init(color: Color) {
self.init(color: color, turbo: true)
}
!
!
!
}
Convenience Initializers
class RaceCar: Car {
var hasTurbo: Bool
init(color: Color, turbo: Bool) {
hasTurbo = turbo
super.init(color: color)
}
!
init(color: Color) {
self.init(color: color, turbo: true)
}
!
!
!
}
class RaceCar: Car {
var hasTurbo: Bool
init(color: Color, turbo: Bool) {
hasTurbo = turbo
super.init(color: color)
}
!
self.init(color: color, turbo: true)
}
!
!
!
}
init(color: Color) {
Convenience Initializers
class RaceCar: Car {
var hasTurbo: Bool
init(color: Color, turbo: Bool) {
hasTurbo = turbo
super.init(color: color)
}
!
self.init(color: color, turbo: true)
}
!
!
!
}
convenience init(color: Color) {
Convenience Initializers
Convenience Initializers
class RaceCar: Car {
var hasTurbo: Bool
init(color: Color, turbo: Bool) {
hasTurbo = turbo
super.init(color: color)
}
!
convenience init(color: Color) {
self.init(color: color, turbo: true)
}
!
convenience init() {
self.init(color: Color(gray: 0.4))
}
}
Convenience Initializers
class RaceCar: Car {
var hasTurbo: Bool
init(color: Color, turbo: Bool) {
hasTurbo = turbo
super.init(color: color)
}
!
convenience init(color: Color) {
self.init(color: color, turbo: true)
}
!
convenience init() {
self.init(color: Color(gray: 0.4))
}
}
Convenience Initializers
class RaceCar: Car {
var hasTurbo: Bool
init(color: Color, turbo: Bool) {
hasTurbo = turbo
super.init(color: color)
}
!
convenience init(color: Color) {
self.init(color: color, turbo: true)
}
!
convenience init() {
self.init(color: Color(gray: 0.4))
}
}
Convenience Initializers
class RaceCar: Car {
var hasTurbo: Bool
init(color: Color, turbo: Bool) {
hasTurbo = turbo
super.init(color: color)
}
!
convenience init(color: Color) {
self.init(color: color, turbo: true)
}
!
convenience init() {
self.init(color: Color(gray: 0.4))
}
}
Convenience Initializers
class RaceCar: Car {
var hasTurbo: Bool
init(color: Color, turbo: Bool) {
hasTurbo = turbo
super.init(color: color)
}
!
convenience init(color: Color) {
self.init(color: color, turbo: true)
}
!
convenience init() {
self.init(color: Color(gray: 0.4))
}
}
Convenience Initializers
class RaceCar: Car {
var hasTurbo: Bool
init(color: Color, turbo: Bool) {
hasTurbo = turbo
super.init(color: color)
}
!
convenience init(color: Color) {
self.init(color: color, turbo: true)
}
!
convenience init() {
self.init(color: Color(gray: 0.4))
}
}
Initializer Inheritance
class FormulaOne: RaceCar {
let minimumWeight = 642
Initializer Inheritance
class FormulaOne: RaceCar {
let minimumWeight = 642
// inherited from RaceCar
init(color: Color, turbo: Bool) {
hasTurbo = turbo
super.init(color: color)
}
convenience init(color: Color) {
self.init(color: color, turbo: true)
}
convenience init() {
self.init(color: Color(gray: 0.4))
}
}
Initializer Inheritance
class FormulaOne: RaceCar {
let minimumWeight = 642
// inherited from RaceCar
init(color: Color, turbo: Bool) {
hasTurbo = turbo
super.init(color: color)
}
convenience init(color: Color) {
self.init(color: color, turbo: true)
}
convenience init() {
self.init(color: Color(gray: 0.4))
}
}
Initializer Inheritance
class FormulaOne: RaceCar {
let minimumWeight = 642
init(color: Color) {
super.init(color: color, turbo: false)
}
!
!
!
}
Initializer Inheritance
class FormulaOne: RaceCar {
let minimumWeight = 642
init(color: Color) {
super.init(color: color, turbo: false)
}
!
// not inherited from RaceCar
init(color: Color, turbo: Bool)
convenience init()
}
Lazy Properties
Lazy Properties
class Game {
var multiplayerManager = MultiplayerManager()
var singlePlayer: Player?
func beginGameWithPlayers(players: Player...) {
!
!
!
!
!
!
}
}
Lazy Properties
class Game {
var multiplayerManager = MultiplayerManager()
var singlePlayer: Player?
func beginGameWithPlayers(players: Player...) {
if players.count == 1 {
singlePlayer = players[0]
}
!
!
!
!
}
}
Lazy Properties
class Game {
var multiplayerManager = MultiplayerManager()
var singlePlayer: Player?
func beginGameWithPlayers(players: Player...) {
if players.count == 1 {
singlePlayer = players[0]
} else {
for player in players {
multiplayerManager.addPlayer(player)
}
}
}
}
class Game {
var singlePlayer: Player?
func beginGameWithPlayers(players: Player...) {
if players.count == 1 {
singlePlayer = players[0]
} else {
for player in players {
multiplayerManager.addPlayer(player)
}
}
}
}
var multiplayerManager = MultiplayerManager()
Lazy Properties
class Game {
var singlePlayer: Player?
func beginGameWithPlayers(players: Player...) {
if players.count == 1 {
singlePlayer = players[0]
} else {
for player in players {
multiplayerManager.addPlayer(player)
}
}
}
}
@lazy var multiplayerManager = MultiplayerManager()
Lazy Properties
Deinitialization
Deinitialization
class FileHandle {
let fileDescriptor: FileDescriptor
init(path: String) {
fileDescriptor = openFile(path)
}
!
!
!
}
Deinitialization
class FileHandle {
let fileDescriptor: FileDescriptor
init(path: String) {
fileDescriptor = openFile(path)
}
deinit {
closeFile(fileDescriptor)
}
}
Initialization
Initialization
Initialize all values before you use them
Set all stored properties first, then call super.init
Initialization
Initialize all values before you use them
Set all stored properties first, then call super.init
Designated initializers only delegate up
Convenience initializers only delegate across
Initialization
Initialize all values before you use them
Set all stored properties first, then call super.init
Designated initializers only delegate up
Convenience initializers only delegate across
Deinitializers are there… if you need them
Closures
Joe Groff
Swift Compiler Engineer
Closures
var clients = ["Pestov", "Buenaventura", "Sreeram", "Babbage"]
!
clients.sort(
!
!
!
println(clients)
Closures
var clients = ["Pestov", "Buenaventura", "Sreeram", "Babbage"]
!
clients.sort(
!
!
!
println(clients)
{
})
Closures
var clients = ["Pestov", "Buenaventura", "Sreeram", "Babbage"]
!
clients.sort(
!
!
!
println(clients)
{(a: String, b: String) -> Bool
})
Closures
var clients = ["Pestov", "Buenaventura", "Sreeram", "Babbage"]
!
clients.sort(
!
!
!
println(clients)
{(a: String, b: String) -> Bool in
})
Closures
var clients = ["Pestov", "Buenaventura", "Sreeram", "Babbage"]
!
clients.sort(
!
!
!
println(clients)
{(a: String, b: String) -> Bool in
return a < b
})
Closures
var clients = ["Pestov", "Buenaventura", "Sreeram", "Babbage"]
!
clients.sort(
!
!
!
println(clients)
in{(a: String, b: String) -> Bool
return a < b
})
Closures
var clients = ["Pestov", "Buenaventura", "Sreeram", "Babbage"]
!
clients.sort(
!
!
!
println(clients)
in{(a: String, b: String) -> Bool
return a < b
})
[Babbage, Buenaventura, Pestov, Sreeram]
var clients = ["Pestov", "Buenaventura", "Sreeram", "Babbage"]
!
clients.sort(
!
!
!
println(clients)
in{(a: String, b: String) -> Bool
})
Closures
var clients = ["Pestov", "Buenaventura", "Sreeram", "Babbage"]
!
clients.sort(
!
!
!
println(clients)
in{(a: String, b: String) -> Bool
return a > b
})
Closures
[Sreeram, Pestov, Buenaventura, Babbage]
var clients = ["Pestov", "Buenaventura", "Sreeram", "Babbage"]
!
clients.sort(
!
!
!
println(clients)
Closures
in{(a: String, b: String) -> Bool
})
var clients = ["Pestov", "Buenaventura", "Sreeram", "Babbage"]
!
clients.sort(
!
!
!
println(clients)
Closures
[Pestov, Sreeram, Babbage, Buenaventura]
in{(a: String, b: String) -> Bool
return countElements(a) < countElements(b)
})
var clients = ["Pestov", "Buenaventura", "Sreeram", "Babbage"]
!
clients.sort(
!
!
!
println(clients)
in{(a: String, b: String) -> Bool
})
Closures
var clients = ["Pestov", "Buenaventura", "Sreeram", "Babbage"]
!
clients.sort(
!
!
!
println(clients)
in{(a: String, b: String) -> Bool
})
Closures
return a < b
var clients = ["Pestov", "Buenaventura", "Sreeram", "Babbage"]
!
clients.sort(
!
!
!
println(clients)
in{(a: String, b: String) -> Bool
})
Closures
return a < b
Type Inference
var clients = ["Pestov", "Buenaventura", "Sreeram", "Babbage"]
!
clients.sort(
!
!
!
println(clients)
in{(a: String, b: String) -> Bool
})
return a < b
Type Inference
var clients = ["Pestov", "Buenaventura", "Sreeram", "Babbage"]
!
clients.sort(
!
!
!
println(clients)
in{(a: String, b: String) -> Bool
})
sort
return a < b
Type Inference
struct Array<T> {
func sort(order: (T, T) -> Bool)
}
Type Inference
struct Array<String> {
func sort(order: (String, String) -> Bool)
}
Type Inference
struct Array<String> {
func sort(order: (String, String) -> Bool)
}
{( : String : String) -> Bool
return
})
a < b
inclients.sort( a , b
Type Inference
struct Array<String> {
func sort(order: (String, String) -> Bool)
}
{
return
})
a < b
inclients.sort( a, b
Implicit Return
{
return
})
a < b
inclients.sort( a, b
Implicit Return
{ inclients.sort( a, b a < b })
a
Implicit Arguments
{ inclients.sort( a, b < })b
Implicit Arguments
{clients.sort( < })$0 $1
Trailing Closures
clients.sort $1$0{ < })(
Trailing Closures
clients.sort $1$0{ < }
Functional Programming
Functional Programming
println(words)
a
aardvark
aardwolf…
Functional Programming
println(words.filter { $0.hasSuffix("gry") })
Functional Programming
println(words.filter { $0.hasSuffix("gry") })
angry
hungry
Functional Programming
println(words.filter { $0.hasSuffix("gry") }
.map { $0.uppercaseString })
Functional Programming
println(words.filter { $0.hasSuffix("gry") }
.map { $0.uppercaseString })
ANGRY
HUNGRY
Functional Programming
println(words.filter { $0.hasSuffix("gry") }
.map { $0.uppercaseString }
.reduce("HULK") { "($0) ($1)" })
Functional Programming
println(words.filter { $0.hasSuffix("gry") }
.map { $0.uppercaseString }
.reduce("HULK") { "($0) ($1)" })
HULK ANGRY HUNGRY
Functional Programming
println(words.filter { $0.hasSuffix("gry") }
.map { $0.uppercaseString }
.reduce("HULK") { "($0) ($1)" })
HULK ANGRY HUNGRY
Functional Programming
println(words.filter { $0.hasSuffix("gry") }
.map { $0.uppercaseString }
.reduce("HULK") { "($0) ($1)" })
Functional Programming
println(
GRR!! HULK ANGRY HUNGRY!!!
words.filter { $0.hasSuffix("gry") }
.map { $0.uppercaseString }
.reduce("HULK") { "($0) ($1)" } )
"GRR!! " +
+ "!!!"
Captures
Captures
func sum(numbers: Int[]) {
var sum = 0
numbers.map {
Captures
func sum(numbers: Int[]) {
var sum = 0
numbers.map {
sum += $0
}
Captures
func sum(numbers: Int[]) {
var sum = 0
numbers.map {
sum += $0
}
Captures
func sum(numbers: Int[]) {
var sum = 0
numbers.map {
sum += $0
}
Captures
func sum(numbers: Int[]) {
var sum = 0
numbers.map {
sum += $0
}
return sum
}
Function Values—Closures
!
!
!
numbers.map {
sum += $0
}
!
!
!
numbers.map
Function Values—Functions
println($0)
{
}
!
!
!
numbers.map (println)
Function Values—Functions
!
!
var indexes = NSMutableIndexSet()
numbers.map
!
Function Values—Methods
indexes.addIndex($0)
{
}
!
!
var indexes = NSMutableIndexSet()
numbers.map
!
(indexes.addIndex)
Function Values—Methods
Closures Are ARC Objects
Closures Are ARC Objects
var onTemperatureChange: (Int) -> Void = {}
onTempChange
Closures Are ARC Objects
var onTemperatureChange: (Int) -> Void = {}
func logTemperatureDifferences(initial: Int) {
var prev = initial
onTempChange
prev
Closures Are ARC Objects
var onTemperatureChange: (Int) -> Void = {}
func logTemperatureDifferences(initial: Int) {
var prev = initial
onTemperatureChange = { next in
println("Changed (next - prev)°F")
prev = next
}
{...}
onTempChange
prev
Closures Are ARC Objects
var onTemperatureChange: (Int) -> Void = {}
func logTemperatureDifferences(initial: Int) {
var prev = initial
onTemperatureChange = { next in
println("Changed (next - prev)°F")
prev = next
}
} // scope ends
{...}
onTempChange
prev
Functions Are ARC Objects
var onTemperatureChange: (Int) -> Void = {}
func logTemperatureDifferences(initial: Int) {
var prev = initial
func log(next: Int) {
println("Changed (next - prev)°F")
prev = next
}
onTempChange
Functions Are ARC Objects
var onTemperatureChange: (Int) -> Void = {}
func logTemperatureDifferences(initial: Int) {
var prev = initial
func log(next: Int) {
println("Changed (next - prev)°F")
prev = next
}
log
onTempChange
prev
Functions Are ARC Objects
var onTemperatureChange: (Int) -> Void = {}
func logTemperatureDifferences(initial: Int) {
var prev = initial
func log(next: Int) {
println("Changed (next - prev)°F")
prev = next
}
onTemperatureChange = log
log
onTempChange
prev
Functions Are ARC Objects
var onTemperatureChange: (Int) -> Void = {}
func logTemperatureDifferences(initial: Int) {
var prev = initial
func log(next: Int) {
println("Changed (next - prev)°F")
prev = next
}
onTemperatureChange = log
} // scope ends
log
onTempChange
prev
Ownership of Captures
Ownership of Captures
class TemperatureNotifier {
var onChange: (Int) -> Void = {}
Ownership of Captures
class TemperatureNotifier {
var onChange: (Int) -> Void = {}
var currentTemp = 72
init() {
onChange = { temp in
}
}
}
currentTemp = temp
Ownership of Captures
class TemperatureNotifier {
var onChange: (Int) -> Void = {}
var currentTemp = 72
init() {
onChange = { temp in
}
}
}
{...}
TempNotifier
currentTemp = temp
Ownership of Captures
class TemperatureNotifier {
var onChange: (Int) -> Void = {}
var currentTemp = 72
init() {
onChange = { temp in
}
}
}
{...}
TempNotifier
currentTemp = tempself.
self
Ownership of Captures
class TemperatureNotifier {
var onChange: (Int) -> Void = {}
var currentTemp = 72
init() {
onChange = { temp in
}
}
}
{...}
TempNotifier
currentTemp = tempself.
self
onChange
Ownership of Captures
class TemperatureNotifier {
var onChange: (Int) -> Void = {}
var currentTemp = 72
init() {
onChange = { temp in
}
}
}
{...}
TempNotifier
currentTemp = tempself.
self
onChange
Ownership of Captures
class TemperatureNotifier {
var onChange: (Int) -> Void = {}
var currentTemp = 72
init() {
onChange = { temp in
}
}
}
{...}
TempNotifier
self
onChange
currentTemp = temp
// error: requires explicit 'self'
class TempNotifier {
var onChange: (Int) -> Void = {}
var currentTemp = 72
!
init() {
onChange = { temp in
Ownership of Captures
currentTemp = tempself.
}
}
}
class TempNotifier {
var onChange: (Int) -> Void = {}
var currentTemp = 72
!
init() {
onChange = { temp in
unowned let uSelf = self
Ownership of Captures
currentTemp = tempself.
}
}
}
class TempNotifier {
var onChange: (Int) -> Void = {}
var currentTemp = 72
!
init() {
onChange = { temp in
unowned let uSelf = self
Ownership of Captures
currentTemp = temp
}
}
}
uSelf.
Capture Lists
class TempNotifier {
var onChange: (Int) -> Void = {}
var currentTemp = 72
!
init() {
currentTemp = tempself.
}
}
}
onChange = { temp in
Capture Lists
class TempNotifier {
var onChange: (Int) -> Void = {}
var currentTemp = 72
!
init() {
currentTemp = tempself.
}
}
}
onChange = {[unowned self] temp in
Capture Lists
class TempNotifier {
var onChange: (Int) -> Void = {}
var currentTemp = 72
!
init() {
currentTemp = tempself.
}
}
}
onChange = {[unowned self] temp in
{...}
TempNotifier
self
onChange
Closures
Closures
Concise, expressive syntax
Closures
Concise, expressive syntax
Simple memory model
Closures
Concise, expressive syntax
Simple memory model
Supports functional programming idioms
Pattern Matching
Joe Groff
Swift Compiler Engineer
func describe(value:
switch value {
case
println("the loneliest number that you'll ever do")
case
println("can be as bad as one")
default:
println("just some number")
}
}
Switch
Int) {
1:
2:
func describe(value:
switch value {
case
println("the loneliest number that you'll ever do")
case
println("can be as bad as one")
default:
println("just some number")
}
}
Switch
"two"
"one"
String) {
:
:
func describe(value:
switch value {
case
println("a few")
case
println("a lot")
default:
println("a ton")
}
}
:
:
String
"two"
"one"
Switch
) {
func describe(value:
switch value {
case
println("a few")
case
println("a lot")
default:
println("a ton")
}
}
:
:5...12
0...4
Int
Switch
) {
enum TrainStatus {
case OnTime
case Delayed
Enumerations
}
enum TrainStatus {
case OnTime
case Delayed
Enumerations
}
(Int)
switch trainStatus {
case .OnTime:
println("on time")
case .Delayed
println("delayed
}
Enumerations
:
")
switch trainStatus {
case .OnTime:
println("on time")
case .Delayed
println("delayed
}
(let minutes)
Enumerations
:
")
switch trainStatus {
case .OnTime:
println("on time")
case .Delayed
println("delayed
}
by (minutes) minutes
(let minutes)
Enumerations
:
")
switch trainStatus {
case .OnTime:
println("on time")
case .Delayed
println("delayed
}
println("let's take (minutes) and come back")
// error: use of unresolved identifier 'minutes'
by (minutes) minutes
(let minutes)
Enumerations
:
")
switch trainStatus {
case .OnTime:
println("on time")
case .Delayed
println("delayed
}
Patterns
:
")
(let minutes)
by (minutes) minutes
switch trainStatus {
case .OnTime:
println("on time")
case .Delayed
println("delayed
}
Patterns
:
")
(let minutes)
by (minutes) minutes
switch trainStatus {
case .OnTime:
println("on time")
case .Delayed
println("delayed
}
Patterns
:
")
(let minutes)
by (minutes) minutes
switch trainStatus {
case .OnTime:
println("on time")
Patterns Compose
switch trainStatus {
case .OnTime:
println("on time")
Patterns Compose
case .Delayed(1):
println("nearly on time")
switch trainStatus {
case .OnTime:
println("on time")
Patterns Compose
case .Delayed(1):
println("nearly on time")
case .Delayed(2...10):
println("almost on time, I swear")
switch trainStatus {
case .OnTime:
println("on time")
Patterns Compose
case .Delayed(1):
println("nearly on time")
case .Delayed(2...10):
println("almost on time, I swear")
case .Delayed(_):
println("it'll get here when it's ready")
enum VacationStatus {
case Traveling(TrainStatus)
case Relaxing(daysLeft: Int)
}
Patterns Compose
Patterns Compose
switch vacationStatus {
Patterns Compose
switch vacationStatus {
case .Traveling(.OnTime):
tweet("Train's on time! Can't wait to get there!")
Patterns Compose
switch vacationStatus {
case .Traveling(.OnTime):
tweet("Train's on time! Can't wait to get there!")
case .Traveling(.Delayed(1...15)):
tweet("Train is delayed.")
Patterns Compose
switch vacationStatus {
case .Traveling(.OnTime):
tweet("Train's on time! Can't wait to get there!")
case .Traveling(.Delayed(1...15)):
tweet("Train is delayed.")
case .Traveling(.Delayed(_)):
tweet("OMG when will this train ride end #railfail")
Patterns Compose
Type Patterns
func tuneUp(car: Car) {
switch car {
Type Patterns
func tuneUp(car: Car) {
switch car {
case let formulaOne as FormulaOne:
Type Patterns
func tuneUp(car: Car) {
switch car {
case let formulaOne as FormulaOne:
Type Patterns
func tuneUp(car: Car) {
switch car {
case let formulaOne as FormulaOne:
Type Patterns
func tuneUp(car: Car) {
switch car {
case let formulaOne as FormulaOne:
formulaOne.enterPit()
Type Patterns
func tuneUp(car: Car) {
switch car {
case let formulaOne as FormulaOne:
formulaOne.enterPit()
case let raceCar as RaceCar:
if raceCar.hasTurbo { raceCar.tuneTurbo() }
Type Patterns
func tuneUp(car: Car) {
switch car {
case let formulaOne as FormulaOne:
formulaOne.enterPit()
case let raceCar as RaceCar:
if raceCar.hasTurbo { raceCar.tuneTurbo() }
fallthrough
Type Patterns
func tuneUp(car: Car) {
switch car {
case let formulaOne as FormulaOne:
formulaOne.enterPit()
case let raceCar as RaceCar:
if raceCar.hasTurbo { raceCar.tuneTurbo() }
fallthrough
default:
car.checkOil()
car.pumpTires()
}
}
Type Patterns
Tuple Patterns
let color = (1.0, 1.0, 1.0, 1.0)
switch color {
case (0.0, 0.5...1.0, let blue, _):
println("Green and (blue * 100)% blue")
Tuple Patterns
let color = (1.0, 1.0, 1.0, 1.0)
switch color {
case (0.0, 0.5...1.0, let blue, _):
println("Green and (blue * 100)% blue")
Tuple Patterns
let color = (1.0, 1.0, 1.0, 1.0)
switch color {
case (0.0, 0.5...1.0, let blue, _):
println("Green and (blue * 100)% blue")
Tuple Patterns
let color = (1.0, 1.0, 1.0, 1.0)
switch color {
case (0.0, 0.5...1.0, let blue, _):
println("Green and (blue * 100)% blue")
Tuple Patterns
let color = (1.0, 1.0, 1.0, 1.0)
switch color {
case (0.0, 0.5...1.0, let blue, _):
println("Green and (blue * 100)% blue")
Tuple Patterns
let color = (1.0, 1.0, 1.0, 1.0)
switch color {
case (0.0, 0.5...1.0, let blue, _):
println("Green and (blue * 100)% blue")
Tuple Patterns
let color = (1.0, 1.0, 1.0, 1.0)
switch color {
case (0.0, 0.5...1.0, let blue, _):
println("Green and (blue * 100)% blue")
case let (r, g, b, 1.0) where r == g && g == b:
println("Opaque grey (r * 100)%")
Tuple Patterns
Validating a Property List
Validating a Property List
func stateFromPlist(list: Dictionary<String, AnyObject>)
Validating a Property List
func stateFromPlist(list: Dictionary<String, AnyObject>)
-> State?
Validating a Property List
func stateFromPlist(list: Dictionary<String, AnyObject>)
-> State?
stateFromPlist(["name": "California",
"population": 38_040_000,
"abbr": "CA"])
State(name: California, population: 38040000, abbr: CA)
Validating a Property List
func stateFromPlist(list: Dictionary<String, AnyObject>)
-> State?
!
stateFromPlist(["name": "California",
"population": "hella peeps",
"abbr": "CA"])
Validating a Property List
func stateFromPlist(list: Dictionary<String, AnyObject>)
-> State?
!
stateFromPlist(["name": "California",
"population": "hella peeps",
"abbr": "CA"])
nil
Validating a Property List
func stateFromPlist(list: Dictionary<String, AnyObject>)
-> State?
!
stateFromPlist(["name": "California",
"population": 38_040_000,
"abbr": "Cali"])
Validating a Property List
func stateFromPlist(list: Dictionary<String, AnyObject>)
-> State?
!
stateFromPlist(["name": "California",
"population": 38_040_000,
"abbr": "Cali"])
nil
Putting Patterns Together
Putting Patterns Together
func stateFromPlist(list: Dictionary<String, AnyObject>)
-> State? {
Putting Patterns Together
func stateFromPlist(list: Dictionary<String, AnyObject>)
-> State? {
var name: NSString?
switch list["name"] {
case
Putting Patterns Together
func stateFromPlist(list: Dictionary<String, AnyObject>)
-> State? {
var name: NSString?
switch list["name"] {
case .Some( ):
Putting Patterns Together
func stateFromPlist(list: Dictionary<String, AnyObject>)
-> State? {
var name: NSString?
switch list["name"] {
case .Some( ):as NSString
Putting Patterns Together
func stateFromPlist(list: Dictionary<String, AnyObject>)
-> State? {
var name: NSString?
switch list["name"] {
case .Some( ):let listName as NSString
Putting Patterns Together
func stateFromPlist(list: Dictionary<String, AnyObject>)
-> State? {
var name: NSString?
switch list["name"] {
case
name = listName
.Some( ):let listName as NSString
Putting Patterns Together
func stateFromPlist(list: Dictionary<String, AnyObject>)
-> State? {
var name: NSString?
switch list["name"] {
case
name = listName
default:
name = nil
}
.Some( ):let listName as NSString
func stateFromPlist(list: Dictionary<String, AnyObject>)
-> State? {
!
switch
case
Putting Patterns Together
list["name"] {
:
name = listName
default:
name = nil
}
var name: NSString?
.Some( )let listName as NSString
func stateFromPlist(list: Dictionary<String, AnyObject>)
-> State? {
!
switch
case
Putting Patterns Together
( , list["population"], list["abbr"])list["name"] {
:.Some( )let listName as NSString
( ,
.Some(let pop as NSNumber),
.Some(let abbr as NSString))
func stateFromPlist(list: Dictionary<String, AnyObject>)
-> State? {
!
switch
case
Putting Patterns Together
( , list["population"], list["abbr"])list["name"] {
.Some( )let listName as NSString
( ,
.Some(let pop as NSNumber),
.Some(let abbr as NSString))
func stateFromPlist(list: Dictionary<String, AnyObject>)
-> State? {
!
switch
case
Putting Patterns Together
( , list["population"], list["abbr"])list["name"] {
where abbr.length == 2:
.Some( )let listName as NSString
( ,
.Some(let pop as NSNumber),
.Some(let abbr as NSString))
func stateFromPlist(list: Dictionary<String, AnyObject>)
-> State? {
!
switch
case
Putting Patterns Together
( , list["population"], list["abbr"])list["name"] {
where abbr.length == 2:
return State(name: listName, population: pop, abbr: abbr)
.Some( )let listName as NSString
( ,
.Some(let pop as NSNumber),
.Some(let abbr as NSString))
func stateFromPlist(list: Dictionary<String, AnyObject>)
-> State? {
!
switch
case
Putting Patterns Together
( , list["population"], list["abbr"])list["name"] {
where abbr.length == 2:
return State(name: listName, population: pop, abbr: abbr)
default:
return nil
.Some( )let listName as NSString
( ,
.Some(let pop as NSNumber),
.Some(let abbr as NSString))
func stateFromPlist(list: Dictionary<String, AnyObject>)
-> State? {
!
switch
case
Putting Patterns Together
( , list["population"], list["abbr"])list["name"] {
where abbr.length == 2:
return State(name: listName, population: pop, abbr: abbr)
default:
return nil
}
}
.Some( )let listName as NSString
Pattern Matching
Pattern Matching
Tests the structure of values
Pattern Matching
Tests the structure of values
Improves readability—Patterns are concise and composable
Pattern Matching
Tests the structure of values
Improves readability—Patterns are concise and composable
Improves safety—Variable bindings are tied to the conditions they depend on
Swift
Swift
Optionals
Swift
Optionals
Memory management
Swift
Optionals
Memory management
Initialization
Swift
Optionals
Memory management
Initialization
Closures
Swift
Optionals
Memory management
Initialization
Closures
Pattern matching
More Information
Dave DeLong
App Frameworks and Developer Tools Evangelist
delong@apple.com
!
Documentation
The Swift Programming Language
Using Swift with Cocoa and Objective-C
http://developer.apple.com
!
Apple Developer Forums
http://devforums.apple.com
Related Sessions
• Introduction to Swift Presidio Tuesday 2:00PM
• Advanced Swift Presidio Thusday 11:30AM
• Integrating Swift with Objective-C Presidio Wednesday 9:00AM
• Swift Interoperability in Depth Presidio Wednesday 3:15PM
• Swift Playgrounds Presidio Wednesday 11:30AM
• Introduction to LLDB and the Swift REPL Mission Thursday 10:15AM
• Advanced Swift Debugging in LLDB Mission Friday 9:00AM
Labs
• Swift Tools Lab A Wednesday 2:00PM
• Swift Tools Lab A Thursday 9:00AM
• Swift Tools Lab A Thursday 2:00PM
• Swift Tools Lab A Friday 9:00AM
• Swift Tools Lab A Friday 2:00PM
Intermediate Swift Language by Apple

Intermediate Swift Language by Apple