Swift 2.2 Design Patterns
COCOACONF AUSTIN
APRIL 2016
Skyline Credit: User:Argash [GFDL (http://www.gnu.org/copyleft/fdl.html) or
CC BY-SA 3.0 (http://creativecommons.org/licenses/by-sa/3.0)], via Wikimedia Commons
@CarlBrwn
Swift 2.2 Design Patterns
COCOACONF AUSTIN
APRIL 2016
Skyline Credit: User:Argash [GFDL (http://www.gnu.org/copyleft/fdl.html) or
CC BY-SA 3.0 (http://creativecommons.org/licenses/by-sa/3.0)], via Wikimedia Commons
@CarlBrwn
[:]?
So, who is this idiot, anyway?
INTRODUCTION
@CarlBrwn
These mean a lot of different things to
different people.
Hopefully they’re of some use to you.
WIDELY RECOGNIZED,
BUT NOT UNDISPUTED
These mean a lot of different things to
different people.
Hopefully they’re of some use to you.
WIDELY RECOGNIZED,
BUT NOT UNDISPUTED
[:]?
Critical Concept in
Software Engineering?
Some think so, others disagree.
[:]?
Simple Enumeration of
Weaknesses in C++
See http://www.norvig.com/design-
patterns/
[:]?
Just Shared Vocabulary?
So, Let’s talk about Swift
(2.2 Version)
PATTERNS ARE
LANGUAGE SPECIFIC
[:]?
Critical Concept in
Software Engineering?
Some think so, others disagree.
[:]?
Simple Enumeration of
Weaknesses in C++
See http://www.norvig.com/design-
patterns/
[:]?
Just Shared Vocabulary?
So, Let’s talk about Swift
(2.2 Version)
& Cocoa
PATTERNS ARE LANGUAGE
(& FRAMEWORK) SPECIFIC
[:]?
Critical Concept in
Software Engineering?
Some think so, others disagree.
[:]?
Simple Enumeration of
Weaknesses in C++
See http://www.norvig.com/design-
patterns/
[:]?
Just Shared Vocabulary?
Design Patterns in Swift 2.2CocoaConf Austin 2016
PATTERN SOURCES FOR TODAY
8

Design Patterns in Swift 2.2CocoaConf Austin 2016
PATTERN SOURCES FOR TODAY
8

Classic Cocoa Design Patterns as
implemented in Swift
Design Patterns in Swift 2.2CocoaConf Austin 2016
PATTERN SOURCES FOR TODAY
8

Classic Cocoa Design Patterns as
implemented in Swift
Some Gang of Four Patterns that lend
themselves to Swift
Design Patterns in Swift 2.2CocoaConf Austin 2016
PATTERN SOURCES FOR TODAY
8

Classic Cocoa Design Patterns as
implemented in Swift
Some Gang of Four Patterns that lend
themselves to Swift
Patterns Apple Documents for Swift
Design Patterns in Swift 2.2CocoaConf Austin 2016
PATTERN SOURCES FOR TODAY
8

Classic Cocoa Design Patterns as
implemented in Swift
Some Gang of Four Patterns that lend
themselves to Swift
Patterns Apple Documents for Swift
Patterns from Other Languages
Design Patterns in Swift 2.2CocoaConf Austin 2016
PATTERN SOURCES FOR TODAY
8

Classic Cocoa Design Patterns as
implemented in Swift
Some Gang of Four Patterns that lend
themselves to Swift
Patterns Apple Documents for Swift
Patterns from Other Languages
Interesting/Potential Swift-specific Patterns

Design Patterns in Swift 2.2CocoaConf Austin 2016
DELEGATE PATTERN
9

Cocoa is said to favor “Composition over Inheritance.” Delegation
is one of the hallmarks of that strategy.
UITableViewDataSource and UITableViewDelegate are
examples.
CLASSIC COCOA PATTERN

Design Patterns in Swift 2.2CocoaConf Austin 2016
DELEGATE PATTERN
9

Cocoa is said to favor “Composition over Inheritance.” Delegation
is one of the hallmarks of that strategy.
UITableViewDataSource and UITableViewDelegate are
examples.
CLASSIC COCOA PATTERN
[:]?
Eases Construction
This is a big reason why we don’t have
to use the “Factory Pattern” in Cocoa/
Swift
Design Patterns in Swift 2.2CocoaConf Austin 2016
DELEGATE PATTERN IN SWIFT
10

var myDS : UITableViewDataSource?
let myTVC = UITableViewController()
let myTV = myTVC.tableView
let num = myDS?.tableView(myTV, numberOfRowsInSection: 0)
let firstHeader = myDS?.tableView?(myTV, titleForHeaderInSection: 0)
Design Patterns in Swift 2.2CocoaConf Austin 2016
DELEGATE PATTERN IN SWIFT
10

var myDS : UITableViewDataSource?
let myTVC = UITableViewController()
let myTV = myTVC.tableView
let num = myDS?.tableView(myTV, numberOfRowsInSection: 0)
let firstHeader = myDS?.tableView?(myTV, titleForHeaderInSection: 0)
1
Test Delegate Optional
The delegate itself must
not be nil (check with ?
and don’t (EVER) use !)
2
Test Method Exists
Put ? after method call to
test for @optional
implementation

Design Patterns in Swift 2.2CocoaConf Austin 2016
ERROR HANDLING PATTERN
11

In Cocoa, methods that produce errors take an NSError pointer
parameter last parameter.
In Swift 2, this is converted to a thrown ErrorType
NEW IN SWIFT 2 - HOOKS INTO COCOA’S (NSError**)

Design Patterns in Swift 2.2CocoaConf Austin 2016
ERROR HANDLING PATTERN
11

In Cocoa, methods that produce errors take an NSError pointer
parameter last parameter.
In Swift 2, this is converted to a thrown ErrorType
NEW IN SWIFT 2 - HOOKS INTO COCOA’S (NSError**)
[]
Not JAva’s Throw
try on each line that might
throw
catch for blocks
Design Patterns in Swift 2.2CocoaConf Austin 2016
ERROR HANDLING PATTERN IN SWIFT
12

- (BOOL)removeItemAtURL:(NSURL *)URL error:(NSError **)error {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *URL = [NSURL fileURLWithPath:@"/path/to/file"];
NSError *error = nil;
BOOL success = [fileManager removeItemAtURL:URL error:&error];
if (!success) {
NSLog(@"Error: %@", error.domain);
}
}
Design Patterns in Swift 2.2CocoaConf Austin 2016
ERROR HANDLING PATTERN IN SWIFT
12

func removeItemAtURL(URL: NSURL) throws {
let fileManager = NSFileManager.defaultManager()
let URL = NSURL.fileURLWithPath("/path/to/file")
do {
try fileManager.removeItemAtURL(URL)
} catch let error as NSError {
print("Error: (error.domain)")
}
}
- (BOOL)removeItemAtURL:(NSURL *)URL error:(NSError **)error {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *URL = [NSURL fileURLWithPath:@"/path/to/file"];
NSError *error = nil;
BOOL success = [fileManager removeItemAtURL:URL error:&error];
if (!success) {
NSLog(@"Error: %@", error.domain);
}
}

Design Patterns in Swift 2.2CocoaConf Austin 2016
OBSERVER PATTERN
13

Key-Value Observing lets you observe any well-behaved Cocoa
property (getter/setter).
It works in Swift *As Long As* the target isKindOf: NSObject
KVO IN SWIFT
Design Patterns in Swift 2.2CocoaConf Austin 2016
OBSERVER PATTERN IN SWIFT
14

Design Patterns in Swift 2.2CocoaConf Austin 2016
OBSERVER PATTERN IN SWIFT
14

objectToObserve.addObserver(self, forKeyPath: "myDate", options: .New,
context: &myContext)
Design Patterns in Swift 2.2CocoaConf Austin 2016
OBSERVER PATTERN IN SWIFT
14

objectToObserve.addObserver(self, forKeyPath: "myDate", options: .New,
context: &myContext)
override func observeValueForKeyPath(keyPath:String?, ofObject object: AnyObject?,
change: [ String : AnyObject ]?, context: UnsafeMutablePointer <Void>) {
if context == &myContext {
if let newValue = change?[NSKeyValueChangeNewKey] {
print("Date changed: (newValue)")
}
} else {
super.observeValueForKeyPath(keyPath, ofObject: object, change: change,
context: context)
}
}
Design Patterns in Swift 2.2CocoaConf Austin 2016
OBSERVER PATTERN IN SWIFT
14

objectToObserve.addObserver(self, forKeyPath: "myDate", options: .New,
context: &myContext)
override func observeValueForKeyPath(keyPath:String?, ofObject object: AnyObject?,
change: [ String : AnyObject ]?, context: UnsafeMutablePointer <Void>) {
if context == &myContext {
if let newValue = change?[NSKeyValueChangeNewKey] {
print("Date changed: (newValue)")
}
} else {
super.observeValueForKeyPath(keyPath, ofObject: object, change: change,
context: context)
}
}
objectToObserve.removeObserver(self, forKeyPath: "myDate", context:
&myContext)
Design Patterns in Swift 2.2CocoaConf Austin 2016
SWIFT-NATIVE KVO *MAYBE* IN SWIFT 4
15


Design Patterns in Swift 2.2CocoaConf Austin 2016
TARGET-ACTION PATTERN
16

In Objective-C, we use @selector to wrap the method name
when adding it as a target.
In Swift 1.x, we just used a String and still had no compiler
typo checking.
In Swift 2.2, we have #selector (SE-0022) and we FINALLY have
compiler type checking.
OSS FTW!!
ATTACH AN ACTION TO A UI ELEMENT
Design Patterns in Swift 2.2CocoaConf Austin 2016
TARGET-ACTION PATTERN IN SWIFT
17

Design Patterns in Swift 2.2CocoaConf Austin 2016
TARGET-ACTION PATTERN IN SWIFT
17

@objc func tappedButton(sender:UIButton!) {
print("tapped button")
}
Design Patterns in Swift 2.2CocoaConf Austin 2016
TARGET-ACTION PATTERN IN SWIFT
17

@objc func tappedButton(sender:UIButton!) {
print("tapped button")
}
#if swift(>=2.2)
myButton.addTarget(self, action: #selector(tappedButton),
forControlEvents: .TouchUpInside)
#else
myButton.addTarget(self, action: "tappedButton",
forControlEvents: .TouchUpInside)
#endif
Design Patterns in Swift 2.2CocoaConf Austin 2016
TARGET-ACTION PATTERN IN SWIFT
17

@objc func tappedButton(sender:UIButton!) {
print("tapped button")
}
#if swift(>=2.2)
myButton.addTarget(self, action: #selector(tappedButton),
forControlEvents: .TouchUpInside)
#else
myButton.addTarget(self, action: "tappedButton",
forControlEvents: .TouchUpInside)
#endif
1
Legacy Objective-C
Only @objc functions can
be made #selectors

Design Patterns in Swift 2.2CocoaConf Austin 2016
SINGLETON PATTERN
18

Fairly common in Cocoa, like [UIApplication
sharedApplication]
In Swift, they’re much simpler to declare (and like ObjC, never
dealloc’ed).
A static type property is guaranteed to be lazily initialized only
once, even when accessed across multiple threads
simultaneously.
SINGLETONS: GLOBAL SHARED INSTANCE
Design Patterns in Swift 2.2CocoaConf Austin 2016
SINGLETON PATTERN IN SWIFT
19

class Singleton {
static let sharedInstance = Singleton()
}
Design Patterns in Swift 2.2CocoaConf Austin 2016
SINGLETON PATTERN IN SWIFT
19

class Singleton {
static let sharedInstance = Singleton()
}
[]
Well, That Was Easy
Obj-C is so much more
complicated
[]
Not All Shared Instances Are Singletons
e.g. NSFileManager

Design Patterns in Swift 2.2CocoaConf Austin 2016
“INTROSPECTION PATTERN”
20

Apple’s Docs call this a pattern. It’s pretty much the same
functionality as we discussed for Delegation.
In my mind, “is this a kind of X class” and “does this implement Y
method” are very limited forms of Introspection.
DYNAMICALLY EXAMINE TYPES AT RUNTIME

Design Patterns in Swift 2.2CocoaConf Austin 2016
“INTROSPECTION PATTERN”
20

Apple’s Docs call this a pattern. It’s pretty much the same
functionality as we discussed for Delegation.
In my mind, “is this a kind of X class” and “does this implement Y
method” are very limited forms of Introspection.
DYNAMICALLY EXAMINE TYPES AT RUNTIME
[]
Not Very Useful
Way harder in pure Swift
than ObjC. Most attempts
bridge NSObjects.

Design Patterns in Swift 2.2CocoaConf Austin 2016
API AVAILABILITY CHECKING “PATTERN”
21

Swift does this at Compile time rather than Runtime (like ObjC).
Calling this a “Pattern” seems like a bit of a stretch to me, but
Apple does.
It is indisputably useful, though.
DECIDE WHETHER AN API IS AVAILABLE

Design Patterns in Swift 2.2CocoaConf Austin 2016
API AVAILABILITY CHECKING “PATTERN”
21

Swift does this at Compile time rather than Runtime (like ObjC).
Calling this a “Pattern” seems like a bit of a stretch to me, but
Apple does.
It is indisputably useful, though.
DECIDE WHETHER AN API IS AVAILABLE
[]
Also for Swift Version #s
Starting with Swift 2.2
Design Patterns in Swift 2.2CocoaConf Austin 2016
API AVAILABILITY CHECKING “PATTERN” IN SWIFT
22

if ([CLLocationManager
instancesRespondToSelector:@selector(requestWhenInUseAuthorization)]) {
// Method is available for use.
} else {
// Method is not available.
}
Design Patterns in Swift 2.2CocoaConf Austin 2016
API AVAILABILITY CHECKING “PATTERN” IN SWIFT
22

let locationManager = CLLocationManager()
if #available(iOS 8.0, OSX 10.10, *) {
locationManager.requestWhenInUseAuthorization()
}
let locationManager = CLLocationManager()
guard #available(iOS 8.0, OSX 10.10, *) else { return }
locationManager.requestWhenInUseAuthorization()
if ([CLLocationManager
instancesRespondToSelector:@selector(requestWhenInUseAuthorization)]) {
// Method is available for use.
} else {
// Method is not available.
}
Design Patterns in Swift 2.2CocoaConf Austin 2016
API AVAILABILITY CHECKING “PATTERN” IN SWIFT
22

let locationManager = CLLocationManager()
if #available(iOS 8.0, OSX 10.10, *) {
locationManager.requestWhenInUseAuthorization()
}
let locationManager = CLLocationManager()
guard #available(iOS 8.0, OSX 10.10, *) else { return }
locationManager.requestWhenInUseAuthorization()
if ([CLLocationManager
instancesRespondToSelector:@selector(requestWhenInUseAuthorization)]) {
// Method is available for use.
} else {
// Method is not available.
}
#if swift(>=2.2)
let tapped = #selector(tappedButton)
#endif

Design Patterns in Swift 2.2CocoaConf Austin 2016
VALUE TYPES/STRUCTS
23

Swift structs can have methods and implement protocols much
like classes, but they’re always passed by value (copied) rather
than passed by reference like objects (which makes them
generally thread-safe, amongst other things).
SWIFT HAS RICH VALUE-TYPES

Design Patterns in Swift 2.2CocoaConf Austin 2016
UBIQUITOUS IMMUTABILITY
24

Pretty much all Swift variables can be declared immutable (with
‘let’), not just certain types like ObjC.
Immutable variables are safer, thread-safe and side-effect free,
which is one claim to fame for functional languages.
NOT JUST FOR STRING/DICT/ARRAY ANYMORE

Design Patterns in Swift 2.2CocoaConf Austin 2016
SEPARATION OF ERRORS
25

Swift has several mechanisms to keep error checking outside and
separate from your business logic.
Checks often get moved from runtime to compile time, and
syntax allows for checks to be isolated to avoid further
complicating already-intricate code.
KEEP ERROR CHECKING AWAY FROM YOUR ALGORITHMS

Design Patterns in Swift 2.2CocoaConf Austin 2016
SEPARATION OF ERRORS 1: if let
26

Much safer than finding out the hard way at runtime.
Unless you use (!)
You don’t use (!), do you? (At least not in shipping apps…)
ENFORCES NIL-CHECK AT COMPILE TIME
Design Patterns in Swift 2.2CocoaConf Austin 2016
SEPARATION OF ERRORS IN SWIFT 1: if let
27

if let obj = obj {
//business logic about object goes here
}

Design Patterns in Swift 2.2CocoaConf Austin 2016
SEPARATION OF ERRORS 2: guard
28

Good for checking at the top of a method
Avoids the “if-let pyramid of doom”
LIKE if-let, BUT WITH CONTINUING SCOPE
Design Patterns in Swift 2.2CocoaConf Austin 2016
SEPARATION OF ERRORS IN SWIFT 2: guard
29

guard let obj = obj as? NSString
where obj.length > 0 else { return }
//business logic about object goes here

Design Patterns in Swift 2.2CocoaConf Austin 2016
SEPARATION OF ERRORS 3: defer
30

Make sure something happens as you exit a scope
SCHEDULE SOMETHING FOR LATER

Design Patterns in Swift 2.2CocoaConf Austin 2016
SEPARATION OF ERRORS 3: defer
30

Make sure something happens as you exit a scope
SCHEDULE SOMETHING FOR LATER
[]
Dearly Departed
@synchronized(dict) {
//use dict safely
}
Design Patterns in Swift 2.2CocoaConf Austin 2016
SEPARATION OF ERRORS IN SWIFT 3: defer
31

let lock = NSLock()
func useLock() {
lock.lock()
defer { lock.unlock() }
//use lock
}

Design Patterns in Swift 2.2CocoaConf Austin 2016
SEPARATION OF ERRORS: try?
32

The try syntax gets scattered all over your code.
Not exactly as good, but at least better than NSError** (or god
forbid C’s return codes and errno).
TRY IS A COUNTER-EXAMPLE THOUGH
Design Patterns in Swift 2.2CocoaConf Austin 2016
SEPARATION OF ERRORS IN SWIFT: try?
33

let url = try fileManager.URLForDirectory(.ApplicationDirectory,
inDomain: .UserDomainMask, appropriateForURL: nil, create: false)
try fileManager.removeItemAtURL(
url.URLByAppendingPathComponent("/path/to/file", isDirectory: true))
if let path = url.URLByAppendingPathComponent("/path/to/file").path {
let files = try fileManager.contentsOfDirectoryAtPath(path)
//do something with files
}
Design Patterns in Swift 2.2CocoaConf Austin 2016
SEPARATION OF ERRORS IN SWIFT: try?
33

let url = try fileManager.URLForDirectory(.ApplicationDirectory,
inDomain: .UserDomainMask, appropriateForURL: nil, create: false)
try fileManager.removeItemAtURL(
url.URLByAppendingPathComponent("/path/to/file", isDirectory: true))
if let path = url.URLByAppendingPathComponent("/path/to/file").path {
let files = try fileManager.contentsOfDirectoryAtPath(path)
//do something with files
}

Design Patterns in Swift 2.2CocoaConf Austin 2016
MONADS (A LA HASKELL MAYBE)
34

Very complicated, at least if you believe most people.
I remember being amazed - *Really amazed* at WWDC 2014
when I realized Apple stuck a Haskell Maybe Monad into Swift,
and used all of 1-character to do it.
FUNCTIONAL PROGRAMMING CONCEPT
Design Patterns in Swift 2.2CocoaConf Austin 2016
”MAYBE” MONAD
35

Design Patterns in Swift 2.2CocoaConf Austin 2016
”MAYBE” MONAD SWIFT OPTIONAL
36

Design Patterns in Swift 2.2CocoaConf Austin 2016
”MAYBE” MONAD SWIFT OPTIONAL
36

Optional

Design Patterns in Swift 2.2CocoaConf Austin 2016
”MAYBE” MONAD SWIFT OPTIONAL
36

Optional

! ?


Design Patterns in Swift 2.2CocoaConf Austin 2016
”MAYBE” MONAD SWIFT OPTIONAL
36

Optional

! ?


?
Design Patterns in Swift 2.2CocoaConf Austin 2016
”MAYBE” MONAD SWIFT OPTIONAL
36

Optional

! ?


?
Design Patterns in Swift 2.2CocoaConf Austin 2016
”MAYBE” MONAD SWIFT OPTIONAL
36

Optional

! ?


?
!
Design Patterns in Swift 2.2CocoaConf Austin 2016
”MAYBE” MONAD SWIFT OPTIONAL
36

Optional

! ?


?
!
[]
“!” Considered HARMFUL
I mean that in a “GOTO” sense.

Design Patterns in Swift 2.2CocoaConf Austin 2016
MAPREDUCE
37

Without this, the Internet as you know it would never have come
to exist, and least not when and how it did.
SEMINAL PAPER BEHIND EARLY GOOGLE
http://static.googleusercontent.com/media/research.google.com/es/us/archive/mapreduce-osdi04.pdf
Design Patterns in Swift 2.2CocoaConf Austin 2016
MAPREDUCE — MAP
38


Design Patterns in Swift 2.2CocoaConf Austin 2016
MAPREDUCE — MAP
38







 


Design Patterns in Swift 2.2CocoaConf Austin 2016
MAPREDUCE — MAP
38







 

[]
Rule of thumb
Same count,
Different Type
Design Patterns in Swift 2.2CocoaConf Austin 2016
MAPREDUCE — MAP IN SWIFT
39
let names = ["RedStripeOnWhite.jpg","OrangeStripeOnWhite.jpg",
"YellowStripeOnWhite.jpg","GreenStripeOnWhite.jpg",
"BlackHorizontal.jpg","BlueStripeOnWhite.jpg",
“IndigoStripeOnWhite.jpg”,"VioletStripeOnWhite.jpg"]
let images = names.map {
UIImage(named: $0)
}
Design Patterns in Swift 2.2CocoaConf Austin 2016
MAPREDUCE — MAP IN SWIFT
39
let names = ["RedStripeOnWhite.jpg","OrangeStripeOnWhite.jpg",
"YellowStripeOnWhite.jpg","GreenStripeOnWhite.jpg",
"BlackHorizontal.jpg","BlueStripeOnWhite.jpg",
“IndigoStripeOnWhite.jpg”,"VioletStripeOnWhite.jpg"]
let images = names.map {
UIImage(named: $0)
}
1
Real WorlD: JSON
I use this a lot to map
JSON Dict to Object/Struct,
but this is more visual
Design Patterns in Swift 2.2CocoaConf Austin 2016
MAPREDUCE — FILTER
40

Design Patterns in Swift 2.2CocoaConf Austin 2016
MAPREDUCE — FILTER
40









Design Patterns in Swift 2.2CocoaConf Austin 2016
MAPREDUCE — FILTER
40









[]
Rule of thumb
Same Type,
Lower Count
Design Patterns in Swift 2.2CocoaConf Austin 2016
MAPREDUCE — FILTER IN SWIFT
41

let colors = images.filter { !mono($0) }
Design Patterns in Swift 2.2CocoaConf Austin 2016
MAPREDUCE — FILTER IN SWIFT
41

let colors = images.filter { !mono($0) }
1
Real WorlD: JSON
I use this a lot to throw out
JSON Dicts I don’t need
Design Patterns in Swift 2.2CocoaConf Austin 2016
MAPREDUCE — REDUCE
42


Design Patterns in Swift 2.2CocoaConf Austin 2016
MAPREDUCE — REDUCE
42







Design Patterns in Swift 2.2CocoaConf Austin 2016
MAPREDUCE — REDUCE
42






[]
Rule of thumb
Different Type,
Count == 1
Design Patterns in Swift 2.2CocoaConf Austin 2016
MAPREDUCE — REDUCE
43

let rainbowImage = ciImages.reduce(CIImage()) { (s, img) -> CIImage? in
let f = CIFilter(name: "CISourceOverCompositing")
f?.setValue(s, forKey: kCIInputBackgroundImageKey)
f?.setValue(img, forKey:kCIInputImageKey)
return f?.outputImage
}
Design Patterns in Swift 2.2CocoaConf Austin 2016
MAPREDUCE — REDUCE
43

let rainbowImage = ciImages.reduce(CIImage()) { (s, img) -> CIImage? in
let f = CIFilter(name: "CISourceOverCompositing")
f?.setValue(s, forKey: kCIInputBackgroundImageKey)
f?.setValue(img, forKey:kCIInputImageKey)
return f?.outputImage
}
Design Patterns in Swift 2.2CocoaConf Austin 2016
MAPREDUCE — REDUCE
44

let rainbowImage = ciImages.reduce(CIImage()) { (s, img) -> CIImage? in
let f = CIFilter(name: "CISourceOverCompositing")
f?.setValue(s, forKey: kCIInputBackgroundImageKey)
f?.setValue(img, forKey:kCIInputImageKey)
return f?.outputImage
}
Design Patterns in Swift 2.2CocoaConf Austin 2016
MAPREDUCE — REDUCE
44

let rainbowImage = ciImages.reduce(CIImage()) { (s, img) -> CIImage? in
let f = CIFilter(name: "CISourceOverCompositing")
f?.setValue(s, forKey: kCIInputBackgroundImageKey)
f?.setValue(img, forKey:kCIInputImageKey)
return f?.outputImage
}
Design Patterns in Swift 2.2CocoaConf Austin 2016
MAPREDUCE — REDUCE
45

let rainbowImage = ciImages.reduce(CIImage()) { (s, img) -> CIImage? in
let f = CIFilter(name: "CISourceOverCompositing")
f?.setValue(s, forKey: kCIInputBackgroundImageKey)
f?.setValue(img, forKey:kCIInputImageKey)
return f?.outputImage
}
Design Patterns in Swift 2.2CocoaConf Austin 2016
MAPREDUCE — REDUCE
45

let rainbowImage = ciImages.reduce(CIImage()) { (s, img) -> CIImage? in
let f = CIFilter(name: "CISourceOverCompositing")
f?.setValue(s, forKey: kCIInputBackgroundImageKey)
f?.setValue(img, forKey:kCIInputImageKey)
return f?.outputImage
}
Design Patterns in Swift 2.2CocoaConf Austin 2016
MAPREDUCE — REDUCE
46

let rainbowImage = ciImages.reduce(CIImage()) { (s, img) -> CIImage? in
let f = CIFilter(name: "CISourceOverCompositing")
f?.setValue(s, forKey: kCIInputBackgroundImageKey)
f?.setValue(img, forKey:kCIInputImageKey)
return f?.outputImage
}
Design Patterns in Swift 2.2CocoaConf Austin 2016
MAPREDUCE — REDUCE
46

let rainbowImage = ciImages.reduce(CIImage()) { (s, img) -> CIImage? in
let f = CIFilter(name: "CISourceOverCompositing")
f?.setValue(s, forKey: kCIInputBackgroundImageKey)
f?.setValue(img, forKey:kCIInputImageKey)
return f?.outputImage
}
Design Patterns in Swift 2.2CocoaConf Austin 2016
MAPREDUCE — REDUCE
47

let rainbowImage = ciImages.reduce(CIImage()) { (s, img) -> CIImage? in
let f = CIFilter(name: "CISourceOverCompositing")
f?.setValue(s, forKey: kCIInputBackgroundImageKey)
f?.setValue(img, forKey:kCIInputImageKey)
return f?.outputImage
}
Design Patterns in Swift 2.2CocoaConf Austin 2016
MAPREDUCE — REDUCE
47

let rainbowImage = ciImages.reduce(CIImage()) { (s, img) -> CIImage? in
let f = CIFilter(name: "CISourceOverCompositing")
f?.setValue(s, forKey: kCIInputBackgroundImageKey)
f?.setValue(img, forKey:kCIInputImageKey)
return f?.outputImage
}
Design Patterns in Swift 2.2CocoaConf Austin 2016
MAPREDUCE — REDUCE
48

let rainbowImage = ciImages.reduce(CIImage()) { (s, img) -> CIImage? in
let f = CIFilter(name: "CISourceOverCompositing")
f?.setValue(s, forKey: kCIInputBackgroundImageKey)
f?.setValue(img, forKey:kCIInputImageKey)
return f?.outputImage
}
Design Patterns in Swift 2.2CocoaConf Austin 2016
MAPREDUCE — REDUCE
48

let rainbowImage = ciImages.reduce(CIImage()) { (s, img) -> CIImage? in
let f = CIFilter(name: "CISourceOverCompositing")
f?.setValue(s, forKey: kCIInputBackgroundImageKey)
f?.setValue(img, forKey:kCIInputImageKey)
return f?.outputImage
}
Design Patterns in Swift 2.2CocoaConf Austin 2016
MAPREDUCE — REDUCE
49

let rainbowImage = ciImages.reduce(CIImage()) { (s, img) -> CIImage? in
let f = CIFilter(name: "CISourceOverCompositing")
f?.setValue(s, forKey: kCIInputBackgroundImageKey)
f?.setValue(img, forKey:kCIInputImageKey)
return f?.outputImage
}
Design Patterns in Swift 2.2CocoaConf Austin 2016
MAPREDUCE — REDUCE
49

let rainbowImage = ciImages.reduce(CIImage()) { (s, img) -> CIImage? in
let f = CIFilter(name: "CISourceOverCompositing")
f?.setValue(s, forKey: kCIInputBackgroundImageKey)
f?.setValue(img, forKey:kCIInputImageKey)
return f?.outputImage
}

Design Patterns in Swift 2.2CocoaConf Austin 2016
MAPREDUCE - WAIT, WAIT, WAIT!!!
50

I have yet to see a case where map/reduce worked consistently
faster on iOS than the equivalent for..in loop, and often it can be
quite a bit slower.
BUT - learn it anyway.
ABOUT SWIFT’S MAPREDUCE PERFORMANCE…

Design Patterns in Swift 2.2CocoaConf Austin 2016
MAPREDUCE - SO WHAT’S THE POINT?
51

…or threads. Or at least, that was the design intent.
I still use it (although I don’t have to), because I’m used to it from
other languages (and I use it with dispatch_groups, despite the
fact they don’t fit on slides).
But Soon (SWIFT 4?? - see earlier email), we’ll have a Swift release
that focuses on asynchronous functionality. And THEN, it will
really, really matter.
MAPREDUCE SPLITS WORK BETWEEN MACHINES

Design Patterns in Swift 2.2CocoaConf Austin 2016
PROTOCOL DEFAULT IMPLEMENTATIONS
52

Protocol Implementations allow for much more useful protocols,
and for much more flexible implementations.
WHOLE NEW WORLD

Design Patterns in Swift 2.2CocoaConf Austin 2016
PROTOCOL EXTENSIONS (W/IMPLEMENTATIONS)
53

Protocol Implementations allow for much more useful protocols,
and for much more flexible implementations.
WHOLE NEW WORLD

Design Patterns in Swift 2.2CocoaConf Austin 2016
PROTOCOL EXTENSIONS (W/IMPLEMENTATIONS)
53

Protocol Implementations allow for much more useful protocols,
and for much more flexible implementations.
WHOLE NEW WORLD
1
Examples are Contrived
And they take a while to
set up, and I’m expecting
this is already going long
2
Big Topic
There’s a whole (VERY
GOOD) WWDC talk on just
this.
Speaking to you all is always a pleasure.
Thank You
Speaking to you all is always a pleasure.
Thank You

Swift 2.2 Design Patterns CocoaConf Austin 2016

  • 1.
    Swift 2.2 DesignPatterns COCOACONF AUSTIN APRIL 2016 Skyline Credit: User:Argash [GFDL (http://www.gnu.org/copyleft/fdl.html) or CC BY-SA 3.0 (http://creativecommons.org/licenses/by-sa/3.0)], via Wikimedia Commons @CarlBrwn
  • 2.
    Swift 2.2 DesignPatterns COCOACONF AUSTIN APRIL 2016 Skyline Credit: User:Argash [GFDL (http://www.gnu.org/copyleft/fdl.html) or CC BY-SA 3.0 (http://creativecommons.org/licenses/by-sa/3.0)], via Wikimedia Commons @CarlBrwn
  • 3.
    [:]? So, who isthis idiot, anyway? INTRODUCTION @CarlBrwn
  • 5.
    These mean alot of different things to different people. Hopefully they’re of some use to you. WIDELY RECOGNIZED, BUT NOT UNDISPUTED
  • 6.
    These mean alot of different things to different people. Hopefully they’re of some use to you. WIDELY RECOGNIZED, BUT NOT UNDISPUTED [:]? Critical Concept in Software Engineering? Some think so, others disagree. [:]? Simple Enumeration of Weaknesses in C++ See http://www.norvig.com/design- patterns/ [:]? Just Shared Vocabulary?
  • 7.
    So, Let’s talkabout Swift (2.2 Version) PATTERNS ARE LANGUAGE SPECIFIC [:]? Critical Concept in Software Engineering? Some think so, others disagree. [:]? Simple Enumeration of Weaknesses in C++ See http://www.norvig.com/design- patterns/ [:]? Just Shared Vocabulary?
  • 8.
    So, Let’s talkabout Swift (2.2 Version) & Cocoa PATTERNS ARE LANGUAGE (& FRAMEWORK) SPECIFIC [:]? Critical Concept in Software Engineering? Some think so, others disagree. [:]? Simple Enumeration of Weaknesses in C++ See http://www.norvig.com/design- patterns/ [:]? Just Shared Vocabulary?
  • 9.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 PATTERN SOURCES FOR TODAY 8 
  • 10.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 PATTERN SOURCES FOR TODAY 8  Classic Cocoa Design Patterns as implemented in Swift
  • 11.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 PATTERN SOURCES FOR TODAY 8  Classic Cocoa Design Patterns as implemented in Swift Some Gang of Four Patterns that lend themselves to Swift
  • 12.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 PATTERN SOURCES FOR TODAY 8  Classic Cocoa Design Patterns as implemented in Swift Some Gang of Four Patterns that lend themselves to Swift Patterns Apple Documents for Swift
  • 13.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 PATTERN SOURCES FOR TODAY 8  Classic Cocoa Design Patterns as implemented in Swift Some Gang of Four Patterns that lend themselves to Swift Patterns Apple Documents for Swift Patterns from Other Languages
  • 14.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 PATTERN SOURCES FOR TODAY 8  Classic Cocoa Design Patterns as implemented in Swift Some Gang of Four Patterns that lend themselves to Swift Patterns Apple Documents for Swift Patterns from Other Languages Interesting/Potential Swift-specific Patterns
  • 15.
     Design Patterns inSwift 2.2CocoaConf Austin 2016 DELEGATE PATTERN 9  Cocoa is said to favor “Composition over Inheritance.” Delegation is one of the hallmarks of that strategy. UITableViewDataSource and UITableViewDelegate are examples. CLASSIC COCOA PATTERN
  • 16.
     Design Patterns inSwift 2.2CocoaConf Austin 2016 DELEGATE PATTERN 9  Cocoa is said to favor “Composition over Inheritance.” Delegation is one of the hallmarks of that strategy. UITableViewDataSource and UITableViewDelegate are examples. CLASSIC COCOA PATTERN [:]? Eases Construction This is a big reason why we don’t have to use the “Factory Pattern” in Cocoa/ Swift
  • 17.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 DELEGATE PATTERN IN SWIFT 10  var myDS : UITableViewDataSource? let myTVC = UITableViewController() let myTV = myTVC.tableView let num = myDS?.tableView(myTV, numberOfRowsInSection: 0) let firstHeader = myDS?.tableView?(myTV, titleForHeaderInSection: 0)
  • 18.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 DELEGATE PATTERN IN SWIFT 10  var myDS : UITableViewDataSource? let myTVC = UITableViewController() let myTV = myTVC.tableView let num = myDS?.tableView(myTV, numberOfRowsInSection: 0) let firstHeader = myDS?.tableView?(myTV, titleForHeaderInSection: 0) 1 Test Delegate Optional The delegate itself must not be nil (check with ? and don’t (EVER) use !) 2 Test Method Exists Put ? after method call to test for @optional implementation
  • 19.
     Design Patterns inSwift 2.2CocoaConf Austin 2016 ERROR HANDLING PATTERN 11  In Cocoa, methods that produce errors take an NSError pointer parameter last parameter. In Swift 2, this is converted to a thrown ErrorType NEW IN SWIFT 2 - HOOKS INTO COCOA’S (NSError**)
  • 20.
     Design Patterns inSwift 2.2CocoaConf Austin 2016 ERROR HANDLING PATTERN 11  In Cocoa, methods that produce errors take an NSError pointer parameter last parameter. In Swift 2, this is converted to a thrown ErrorType NEW IN SWIFT 2 - HOOKS INTO COCOA’S (NSError**) [] Not JAva’s Throw try on each line that might throw catch for blocks
  • 21.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 ERROR HANDLING PATTERN IN SWIFT 12  - (BOOL)removeItemAtURL:(NSURL *)URL error:(NSError **)error { NSFileManager *fileManager = [NSFileManager defaultManager]; NSURL *URL = [NSURL fileURLWithPath:@"/path/to/file"]; NSError *error = nil; BOOL success = [fileManager removeItemAtURL:URL error:&error]; if (!success) { NSLog(@"Error: %@", error.domain); } }
  • 22.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 ERROR HANDLING PATTERN IN SWIFT 12  func removeItemAtURL(URL: NSURL) throws { let fileManager = NSFileManager.defaultManager() let URL = NSURL.fileURLWithPath("/path/to/file") do { try fileManager.removeItemAtURL(URL) } catch let error as NSError { print("Error: (error.domain)") } } - (BOOL)removeItemAtURL:(NSURL *)URL error:(NSError **)error { NSFileManager *fileManager = [NSFileManager defaultManager]; NSURL *URL = [NSURL fileURLWithPath:@"/path/to/file"]; NSError *error = nil; BOOL success = [fileManager removeItemAtURL:URL error:&error]; if (!success) { NSLog(@"Error: %@", error.domain); } }
  • 23.
     Design Patterns inSwift 2.2CocoaConf Austin 2016 OBSERVER PATTERN 13  Key-Value Observing lets you observe any well-behaved Cocoa property (getter/setter). It works in Swift *As Long As* the target isKindOf: NSObject KVO IN SWIFT
  • 24.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 OBSERVER PATTERN IN SWIFT 14 
  • 25.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 OBSERVER PATTERN IN SWIFT 14  objectToObserve.addObserver(self, forKeyPath: "myDate", options: .New, context: &myContext)
  • 26.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 OBSERVER PATTERN IN SWIFT 14  objectToObserve.addObserver(self, forKeyPath: "myDate", options: .New, context: &myContext) override func observeValueForKeyPath(keyPath:String?, ofObject object: AnyObject?, change: [ String : AnyObject ]?, context: UnsafeMutablePointer <Void>) { if context == &myContext { if let newValue = change?[NSKeyValueChangeNewKey] { print("Date changed: (newValue)") } } else { super.observeValueForKeyPath(keyPath, ofObject: object, change: change, context: context) } }
  • 27.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 OBSERVER PATTERN IN SWIFT 14  objectToObserve.addObserver(self, forKeyPath: "myDate", options: .New, context: &myContext) override func observeValueForKeyPath(keyPath:String?, ofObject object: AnyObject?, change: [ String : AnyObject ]?, context: UnsafeMutablePointer <Void>) { if context == &myContext { if let newValue = change?[NSKeyValueChangeNewKey] { print("Date changed: (newValue)") } } else { super.observeValueForKeyPath(keyPath, ofObject: object, change: change, context: context) } } objectToObserve.removeObserver(self, forKeyPath: "myDate", context: &myContext)
  • 28.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 SWIFT-NATIVE KVO *MAYBE* IN SWIFT 4 15 
  • 29.
     Design Patterns inSwift 2.2CocoaConf Austin 2016 TARGET-ACTION PATTERN 16  In Objective-C, we use @selector to wrap the method name when adding it as a target. In Swift 1.x, we just used a String and still had no compiler typo checking. In Swift 2.2, we have #selector (SE-0022) and we FINALLY have compiler type checking. OSS FTW!! ATTACH AN ACTION TO A UI ELEMENT
  • 30.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 TARGET-ACTION PATTERN IN SWIFT 17 
  • 31.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 TARGET-ACTION PATTERN IN SWIFT 17  @objc func tappedButton(sender:UIButton!) { print("tapped button") }
  • 32.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 TARGET-ACTION PATTERN IN SWIFT 17  @objc func tappedButton(sender:UIButton!) { print("tapped button") } #if swift(>=2.2) myButton.addTarget(self, action: #selector(tappedButton), forControlEvents: .TouchUpInside) #else myButton.addTarget(self, action: "tappedButton", forControlEvents: .TouchUpInside) #endif
  • 33.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 TARGET-ACTION PATTERN IN SWIFT 17  @objc func tappedButton(sender:UIButton!) { print("tapped button") } #if swift(>=2.2) myButton.addTarget(self, action: #selector(tappedButton), forControlEvents: .TouchUpInside) #else myButton.addTarget(self, action: "tappedButton", forControlEvents: .TouchUpInside) #endif 1 Legacy Objective-C Only @objc functions can be made #selectors
  • 34.
     Design Patterns inSwift 2.2CocoaConf Austin 2016 SINGLETON PATTERN 18  Fairly common in Cocoa, like [UIApplication sharedApplication] In Swift, they’re much simpler to declare (and like ObjC, never dealloc’ed). A static type property is guaranteed to be lazily initialized only once, even when accessed across multiple threads simultaneously. SINGLETONS: GLOBAL SHARED INSTANCE
  • 35.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 SINGLETON PATTERN IN SWIFT 19  class Singleton { static let sharedInstance = Singleton() }
  • 36.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 SINGLETON PATTERN IN SWIFT 19  class Singleton { static let sharedInstance = Singleton() } [] Well, That Was Easy Obj-C is so much more complicated [] Not All Shared Instances Are Singletons e.g. NSFileManager
  • 37.
     Design Patterns inSwift 2.2CocoaConf Austin 2016 “INTROSPECTION PATTERN” 20  Apple’s Docs call this a pattern. It’s pretty much the same functionality as we discussed for Delegation. In my mind, “is this a kind of X class” and “does this implement Y method” are very limited forms of Introspection. DYNAMICALLY EXAMINE TYPES AT RUNTIME
  • 38.
     Design Patterns inSwift 2.2CocoaConf Austin 2016 “INTROSPECTION PATTERN” 20  Apple’s Docs call this a pattern. It’s pretty much the same functionality as we discussed for Delegation. In my mind, “is this a kind of X class” and “does this implement Y method” are very limited forms of Introspection. DYNAMICALLY EXAMINE TYPES AT RUNTIME [] Not Very Useful Way harder in pure Swift than ObjC. Most attempts bridge NSObjects.
  • 39.
     Design Patterns inSwift 2.2CocoaConf Austin 2016 API AVAILABILITY CHECKING “PATTERN” 21  Swift does this at Compile time rather than Runtime (like ObjC). Calling this a “Pattern” seems like a bit of a stretch to me, but Apple does. It is indisputably useful, though. DECIDE WHETHER AN API IS AVAILABLE
  • 40.
     Design Patterns inSwift 2.2CocoaConf Austin 2016 API AVAILABILITY CHECKING “PATTERN” 21  Swift does this at Compile time rather than Runtime (like ObjC). Calling this a “Pattern” seems like a bit of a stretch to me, but Apple does. It is indisputably useful, though. DECIDE WHETHER AN API IS AVAILABLE [] Also for Swift Version #s Starting with Swift 2.2
  • 41.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 API AVAILABILITY CHECKING “PATTERN” IN SWIFT 22  if ([CLLocationManager instancesRespondToSelector:@selector(requestWhenInUseAuthorization)]) { // Method is available for use. } else { // Method is not available. }
  • 42.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 API AVAILABILITY CHECKING “PATTERN” IN SWIFT 22  let locationManager = CLLocationManager() if #available(iOS 8.0, OSX 10.10, *) { locationManager.requestWhenInUseAuthorization() } let locationManager = CLLocationManager() guard #available(iOS 8.0, OSX 10.10, *) else { return } locationManager.requestWhenInUseAuthorization() if ([CLLocationManager instancesRespondToSelector:@selector(requestWhenInUseAuthorization)]) { // Method is available for use. } else { // Method is not available. }
  • 43.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 API AVAILABILITY CHECKING “PATTERN” IN SWIFT 22  let locationManager = CLLocationManager() if #available(iOS 8.0, OSX 10.10, *) { locationManager.requestWhenInUseAuthorization() } let locationManager = CLLocationManager() guard #available(iOS 8.0, OSX 10.10, *) else { return } locationManager.requestWhenInUseAuthorization() if ([CLLocationManager instancesRespondToSelector:@selector(requestWhenInUseAuthorization)]) { // Method is available for use. } else { // Method is not available. } #if swift(>=2.2) let tapped = #selector(tappedButton) #endif
  • 44.
     Design Patterns inSwift 2.2CocoaConf Austin 2016 VALUE TYPES/STRUCTS 23  Swift structs can have methods and implement protocols much like classes, but they’re always passed by value (copied) rather than passed by reference like objects (which makes them generally thread-safe, amongst other things). SWIFT HAS RICH VALUE-TYPES
  • 45.
     Design Patterns inSwift 2.2CocoaConf Austin 2016 UBIQUITOUS IMMUTABILITY 24  Pretty much all Swift variables can be declared immutable (with ‘let’), not just certain types like ObjC. Immutable variables are safer, thread-safe and side-effect free, which is one claim to fame for functional languages. NOT JUST FOR STRING/DICT/ARRAY ANYMORE
  • 46.
     Design Patterns inSwift 2.2CocoaConf Austin 2016 SEPARATION OF ERRORS 25  Swift has several mechanisms to keep error checking outside and separate from your business logic. Checks often get moved from runtime to compile time, and syntax allows for checks to be isolated to avoid further complicating already-intricate code. KEEP ERROR CHECKING AWAY FROM YOUR ALGORITHMS
  • 47.
     Design Patterns inSwift 2.2CocoaConf Austin 2016 SEPARATION OF ERRORS 1: if let 26  Much safer than finding out the hard way at runtime. Unless you use (!) You don’t use (!), do you? (At least not in shipping apps…) ENFORCES NIL-CHECK AT COMPILE TIME
  • 48.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 SEPARATION OF ERRORS IN SWIFT 1: if let 27  if let obj = obj { //business logic about object goes here }
  • 49.
     Design Patterns inSwift 2.2CocoaConf Austin 2016 SEPARATION OF ERRORS 2: guard 28  Good for checking at the top of a method Avoids the “if-let pyramid of doom” LIKE if-let, BUT WITH CONTINUING SCOPE
  • 50.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 SEPARATION OF ERRORS IN SWIFT 2: guard 29  guard let obj = obj as? NSString where obj.length > 0 else { return } //business logic about object goes here
  • 51.
     Design Patterns inSwift 2.2CocoaConf Austin 2016 SEPARATION OF ERRORS 3: defer 30  Make sure something happens as you exit a scope SCHEDULE SOMETHING FOR LATER
  • 52.
     Design Patterns inSwift 2.2CocoaConf Austin 2016 SEPARATION OF ERRORS 3: defer 30  Make sure something happens as you exit a scope SCHEDULE SOMETHING FOR LATER [] Dearly Departed @synchronized(dict) { //use dict safely }
  • 53.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 SEPARATION OF ERRORS IN SWIFT 3: defer 31  let lock = NSLock() func useLock() { lock.lock() defer { lock.unlock() } //use lock }
  • 54.
     Design Patterns inSwift 2.2CocoaConf Austin 2016 SEPARATION OF ERRORS: try? 32  The try syntax gets scattered all over your code. Not exactly as good, but at least better than NSError** (or god forbid C’s return codes and errno). TRY IS A COUNTER-EXAMPLE THOUGH
  • 55.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 SEPARATION OF ERRORS IN SWIFT: try? 33  let url = try fileManager.URLForDirectory(.ApplicationDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: false) try fileManager.removeItemAtURL( url.URLByAppendingPathComponent("/path/to/file", isDirectory: true)) if let path = url.URLByAppendingPathComponent("/path/to/file").path { let files = try fileManager.contentsOfDirectoryAtPath(path) //do something with files }
  • 56.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 SEPARATION OF ERRORS IN SWIFT: try? 33  let url = try fileManager.URLForDirectory(.ApplicationDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: false) try fileManager.removeItemAtURL( url.URLByAppendingPathComponent("/path/to/file", isDirectory: true)) if let path = url.URLByAppendingPathComponent("/path/to/file").path { let files = try fileManager.contentsOfDirectoryAtPath(path) //do something with files }
  • 57.
     Design Patterns inSwift 2.2CocoaConf Austin 2016 MONADS (A LA HASKELL MAYBE) 34  Very complicated, at least if you believe most people. I remember being amazed - *Really amazed* at WWDC 2014 when I realized Apple stuck a Haskell Maybe Monad into Swift, and used all of 1-character to do it. FUNCTIONAL PROGRAMMING CONCEPT
  • 58.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 ”MAYBE” MONAD 35 
  • 59.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 ”MAYBE” MONAD SWIFT OPTIONAL 36 
  • 60.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 ”MAYBE” MONAD SWIFT OPTIONAL 36  Optional 
  • 61.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 ”MAYBE” MONAD SWIFT OPTIONAL 36  Optional  ! ?  
  • 62.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 ”MAYBE” MONAD SWIFT OPTIONAL 36  Optional  ! ?   ?
  • 63.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 ”MAYBE” MONAD SWIFT OPTIONAL 36  Optional  ! ?   ?
  • 64.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 ”MAYBE” MONAD SWIFT OPTIONAL 36  Optional  ! ?   ? !
  • 65.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 ”MAYBE” MONAD SWIFT OPTIONAL 36  Optional  ! ?   ? ! [] “!” Considered HARMFUL I mean that in a “GOTO” sense.
  • 66.
     Design Patterns inSwift 2.2CocoaConf Austin 2016 MAPREDUCE 37  Without this, the Internet as you know it would never have come to exist, and least not when and how it did. SEMINAL PAPER BEHIND EARLY GOOGLE http://static.googleusercontent.com/media/research.google.com/es/us/archive/mapreduce-osdi04.pdf
  • 67.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 MAPREDUCE — MAP 38 
  • 68.
     Design Patterns inSwift 2.2CocoaConf Austin 2016 MAPREDUCE — MAP 38          
  • 69.
     Design Patterns inSwift 2.2CocoaConf Austin 2016 MAPREDUCE — MAP 38           [] Rule of thumb Same count, Different Type
  • 70.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 MAPREDUCE — MAP IN SWIFT 39 let names = ["RedStripeOnWhite.jpg","OrangeStripeOnWhite.jpg", "YellowStripeOnWhite.jpg","GreenStripeOnWhite.jpg", "BlackHorizontal.jpg","BlueStripeOnWhite.jpg", “IndigoStripeOnWhite.jpg”,"VioletStripeOnWhite.jpg"] let images = names.map { UIImage(named: $0) }
  • 71.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 MAPREDUCE — MAP IN SWIFT 39 let names = ["RedStripeOnWhite.jpg","OrangeStripeOnWhite.jpg", "YellowStripeOnWhite.jpg","GreenStripeOnWhite.jpg", "BlackHorizontal.jpg","BlueStripeOnWhite.jpg", “IndigoStripeOnWhite.jpg”,"VioletStripeOnWhite.jpg"] let images = names.map { UIImage(named: $0) } 1 Real WorlD: JSON I use this a lot to map JSON Dict to Object/Struct, but this is more visual
  • 72.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 MAPREDUCE — FILTER 40 
  • 73.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 MAPREDUCE — FILTER 40         
  • 74.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 MAPREDUCE — FILTER 40          [] Rule of thumb Same Type, Lower Count
  • 75.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 MAPREDUCE — FILTER IN SWIFT 41  let colors = images.filter { !mono($0) }
  • 76.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 MAPREDUCE — FILTER IN SWIFT 41  let colors = images.filter { !mono($0) } 1 Real WorlD: JSON I use this a lot to throw out JSON Dicts I don’t need
  • 77.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 MAPREDUCE — REDUCE 42 
  • 78.
     Design Patterns inSwift 2.2CocoaConf Austin 2016 MAPREDUCE — REDUCE 42      
  • 79.
     Design Patterns inSwift 2.2CocoaConf Austin 2016 MAPREDUCE — REDUCE 42       [] Rule of thumb Different Type, Count == 1
  • 80.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 MAPREDUCE — REDUCE 43  let rainbowImage = ciImages.reduce(CIImage()) { (s, img) -> CIImage? in let f = CIFilter(name: "CISourceOverCompositing") f?.setValue(s, forKey: kCIInputBackgroundImageKey) f?.setValue(img, forKey:kCIInputImageKey) return f?.outputImage }
  • 81.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 MAPREDUCE — REDUCE 43  let rainbowImage = ciImages.reduce(CIImage()) { (s, img) -> CIImage? in let f = CIFilter(name: "CISourceOverCompositing") f?.setValue(s, forKey: kCIInputBackgroundImageKey) f?.setValue(img, forKey:kCIInputImageKey) return f?.outputImage }
  • 82.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 MAPREDUCE — REDUCE 44  let rainbowImage = ciImages.reduce(CIImage()) { (s, img) -> CIImage? in let f = CIFilter(name: "CISourceOverCompositing") f?.setValue(s, forKey: kCIInputBackgroundImageKey) f?.setValue(img, forKey:kCIInputImageKey) return f?.outputImage }
  • 83.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 MAPREDUCE — REDUCE 44  let rainbowImage = ciImages.reduce(CIImage()) { (s, img) -> CIImage? in let f = CIFilter(name: "CISourceOverCompositing") f?.setValue(s, forKey: kCIInputBackgroundImageKey) f?.setValue(img, forKey:kCIInputImageKey) return f?.outputImage }
  • 84.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 MAPREDUCE — REDUCE 45  let rainbowImage = ciImages.reduce(CIImage()) { (s, img) -> CIImage? in let f = CIFilter(name: "CISourceOverCompositing") f?.setValue(s, forKey: kCIInputBackgroundImageKey) f?.setValue(img, forKey:kCIInputImageKey) return f?.outputImage }
  • 85.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 MAPREDUCE — REDUCE 45  let rainbowImage = ciImages.reduce(CIImage()) { (s, img) -> CIImage? in let f = CIFilter(name: "CISourceOverCompositing") f?.setValue(s, forKey: kCIInputBackgroundImageKey) f?.setValue(img, forKey:kCIInputImageKey) return f?.outputImage }
  • 86.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 MAPREDUCE — REDUCE 46  let rainbowImage = ciImages.reduce(CIImage()) { (s, img) -> CIImage? in let f = CIFilter(name: "CISourceOverCompositing") f?.setValue(s, forKey: kCIInputBackgroundImageKey) f?.setValue(img, forKey:kCIInputImageKey) return f?.outputImage }
  • 87.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 MAPREDUCE — REDUCE 46  let rainbowImage = ciImages.reduce(CIImage()) { (s, img) -> CIImage? in let f = CIFilter(name: "CISourceOverCompositing") f?.setValue(s, forKey: kCIInputBackgroundImageKey) f?.setValue(img, forKey:kCIInputImageKey) return f?.outputImage }
  • 88.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 MAPREDUCE — REDUCE 47  let rainbowImage = ciImages.reduce(CIImage()) { (s, img) -> CIImage? in let f = CIFilter(name: "CISourceOverCompositing") f?.setValue(s, forKey: kCIInputBackgroundImageKey) f?.setValue(img, forKey:kCIInputImageKey) return f?.outputImage }
  • 89.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 MAPREDUCE — REDUCE 47  let rainbowImage = ciImages.reduce(CIImage()) { (s, img) -> CIImage? in let f = CIFilter(name: "CISourceOverCompositing") f?.setValue(s, forKey: kCIInputBackgroundImageKey) f?.setValue(img, forKey:kCIInputImageKey) return f?.outputImage }
  • 90.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 MAPREDUCE — REDUCE 48  let rainbowImage = ciImages.reduce(CIImage()) { (s, img) -> CIImage? in let f = CIFilter(name: "CISourceOverCompositing") f?.setValue(s, forKey: kCIInputBackgroundImageKey) f?.setValue(img, forKey:kCIInputImageKey) return f?.outputImage }
  • 91.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 MAPREDUCE — REDUCE 48  let rainbowImage = ciImages.reduce(CIImage()) { (s, img) -> CIImage? in let f = CIFilter(name: "CISourceOverCompositing") f?.setValue(s, forKey: kCIInputBackgroundImageKey) f?.setValue(img, forKey:kCIInputImageKey) return f?.outputImage }
  • 92.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 MAPREDUCE — REDUCE 49  let rainbowImage = ciImages.reduce(CIImage()) { (s, img) -> CIImage? in let f = CIFilter(name: "CISourceOverCompositing") f?.setValue(s, forKey: kCIInputBackgroundImageKey) f?.setValue(img, forKey:kCIInputImageKey) return f?.outputImage }
  • 93.
    Design Patterns inSwift 2.2CocoaConf Austin 2016 MAPREDUCE — REDUCE 49  let rainbowImage = ciImages.reduce(CIImage()) { (s, img) -> CIImage? in let f = CIFilter(name: "CISourceOverCompositing") f?.setValue(s, forKey: kCIInputBackgroundImageKey) f?.setValue(img, forKey:kCIInputImageKey) return f?.outputImage }
  • 94.
     Design Patterns inSwift 2.2CocoaConf Austin 2016 MAPREDUCE - WAIT, WAIT, WAIT!!! 50  I have yet to see a case where map/reduce worked consistently faster on iOS than the equivalent for..in loop, and often it can be quite a bit slower. BUT - learn it anyway. ABOUT SWIFT’S MAPREDUCE PERFORMANCE…
  • 95.
     Design Patterns inSwift 2.2CocoaConf Austin 2016 MAPREDUCE - SO WHAT’S THE POINT? 51  …or threads. Or at least, that was the design intent. I still use it (although I don’t have to), because I’m used to it from other languages (and I use it with dispatch_groups, despite the fact they don’t fit on slides). But Soon (SWIFT 4?? - see earlier email), we’ll have a Swift release that focuses on asynchronous functionality. And THEN, it will really, really matter. MAPREDUCE SPLITS WORK BETWEEN MACHINES
  • 96.
     Design Patterns inSwift 2.2CocoaConf Austin 2016 PROTOCOL DEFAULT IMPLEMENTATIONS 52  Protocol Implementations allow for much more useful protocols, and for much more flexible implementations. WHOLE NEW WORLD
  • 97.
     Design Patterns inSwift 2.2CocoaConf Austin 2016 PROTOCOL EXTENSIONS (W/IMPLEMENTATIONS) 53  Protocol Implementations allow for much more useful protocols, and for much more flexible implementations. WHOLE NEW WORLD
  • 98.
     Design Patterns inSwift 2.2CocoaConf Austin 2016 PROTOCOL EXTENSIONS (W/IMPLEMENTATIONS) 53  Protocol Implementations allow for much more useful protocols, and for much more flexible implementations. WHOLE NEW WORLD 1 Examples are Contrived And they take a while to set up, and I’m expecting this is already going long 2 Big Topic There’s a whole (VERY GOOD) WWDC talk on just this.
  • 99.
    Speaking to youall is always a pleasure. Thank You
  • 100.
    Speaking to youall is always a pleasure. Thank You