Practical Protocols with Associated Types

59
PATs IRL @NatashaTheRobot

Transcript of Practical Protocols with Associated Types

Page 1: Practical Protocols with Associated Types

PATs IRL@NatashaTheRobot

Page 2: Practical Protocols with Associated Types

Protocol-Oriented Programming in Swift Dave Abrahams Professor of Blowing-Your-Mind

Page 3: Practical Protocols with Associated Types
Page 4: Practical Protocols with Associated Types

–- Professor of Blowing-Your-Mind

"Swift is a Protocol-Oriented Programming Language"

Page 5: Practical Protocols with Associated Types

Protocols with Associated Types 🤔

Page 6: Practical Protocols with Associated Types
Page 7: Practical Protocols with Associated Types
Page 8: Practical Protocols with Associated Types
Page 9: Practical Protocols with Associated Types
Page 10: Practical Protocols with Associated Types
Page 11: Practical Protocols with Associated Types

Protocols with Associated Types 🤗

Page 12: Practical Protocols with Associated Types

• Models

• Storyboards

• Networking

Page 13: Practical Protocols with Associated Types

PATs 💖 Models

Page 14: Practical Protocols with Associated Types
Page 15: Practical Protocols with Associated Types
Page 16: Practical Protocols with Associated Types

protocol HasInit { init() }

class Pokemon<Power: HasInit> { func attack() -> Power { return Power() } }

Page 17: Practical Protocols with Associated Types

// power types struct 🌧: HasInit { } struct 🌩: HasInit { } struct 🔥: HasInit { }

Page 18: Practical Protocols with Associated Types

class Pikachu: Pokemon<🌩> {} class Vaporeon: Pokemon<🌧> {}

let pikachu = Pikachu() pikachu.attack() // 🌩

let vaporeon = Vaporeon() vaporeon.attack() // 🌧

Page 19: Practical Protocols with Associated Types
Page 20: Practical Protocols with Associated Types

Mixins and Traits in Swift 2.0 by Matthijs Hollemans

Page 21: Practical Protocols with Associated Types

Mixins and Traits in Swift 2.0 by Matthijs Hollemans

Page 22: Practical Protocols with Associated Types

protocol PowerTrait { associatedtype Power: HasInit func attack() -> Power }

extension PowerTrait { func attack() -> Power { return Power() } }

Page 23: Practical Protocols with Associated Types

struct Pikachu: PowerTrait { associatedtype Power = 🌩 }

struct Vaporeon: PowerTrait { // 🌧 is inferred as the associated type func attack() -> 🌧 { // custom attack logic return 🌧() } }

Page 24: Practical Protocols with Associated Types
Page 25: Practical Protocols with Associated Types

PATs 💖 Storyboards

Page 26: Practical Protocols with Associated Types
Page 27: Practical Protocols with Associated Types
Page 28: Practical Protocols with Associated Types

override func prepare(for segue: UIStoryboardSegue, sender: AnyObject?) { switch segueIdentifier(forSegue: segue) { case .StatueOfLibertyAdventure: let statueOfLibertyVC = segue.destinationViewController as? StatueOfLiberityViewController statueOfLibertyVC?.user = user case .EmpireStateAdventure: let empireStateVC = segue.destinationViewController as? EmpireStateViewController

empireStateVC?.friends = [friend1, friend2]

Page 29: Practical Protocols with Associated Types

protocol Injectable { associatedtype Item func inject(item: Item) func assertDependencies() }

Page 30: Practical Protocols with Associated Types

class AdventureDetailViewController: UIViewController, Injectable {

private var user: User! override func viewDidLoad() { super.viewDidLoad()

assertDependencies() // Do any additional setup after loading the view. } func inject(item: User) { user = item } func assertDependencies() { assert(user != nil) }

}

Page 31: Practical Protocols with Associated Types

override func prepare(for segue: UIStoryboardSegue, sender: AnyObject?) { switch segueIdentifier(forSegue: segue) { case .StatueOfLibertyAdventure: let statueOfLibertyVC = segue.destinationViewController as? StatueOfLiberityViewController statueOfLibertyVC?.inject(item: user) case .EmpireStateAdventure: let empireStateVC = segue.destinationViewController as? EmpireStateViewController

empireStateVC?.inject(item: [friend1, friend2])

Page 32: Practical Protocols with Associated Types
Page 33: Practical Protocols with Associated Types

PATs 💖 Networking

Page 34: Practical Protocols with Associated Types
Page 35: Practical Protocols with Associated Types

struct FoodService { func get(completionHandler: Result<[Food]> -> Void) { // make asynchronous API call // and return appropriate result } }

Page 36: Practical Protocols with Associated Types

enum Result<T> { case Success(T) case Failure(ErrorType) }

Page 37: Practical Protocols with Associated Types

struct FoodService { func get(completionHandler: Result<[Food]> -> Void) { // make asynchronous API call // and return appropriate result } }

Page 38: Practical Protocols with Associated Types

// NYCFoodViewController

var dataSource = [Food]() { didSet { tableView.reloadData() } }

override func viewDidLoad() { super.viewDidLoad() getFood() }

private func getFood() { FoodService().get() { [weak self] result in switch result { case .Success(let food): self?.dataSource = food case .Failure(let error): self?.showError(error) } } }

Page 39: Practical Protocols with Associated Types

View Controller Tests?!!! 😱

Page 40: Practical Protocols with Associated Types

// NYCFoodViewController

private func getFood() { FoodService().get() { [weak self] result in switch result { case .Success(let food): self?.dataSource = food case .Failure(let error): self?.showError(error) } } }

Page 41: Practical Protocols with Associated Types

// NYCFoodViewController

func getFood(fromService service: FoodService) {

service.getFood() { [weak self] result in // handle result } }

Page 42: Practical Protocols with Associated Types

// NYCFoodViewControllerTests

func testFetchFood() { viewController.getFood(fromService: FoodService()) // 🤔 now what? }

Page 43: Practical Protocols with Associated Types

struct FoodService { func get(completionHandler: Result<[Food]> -> Void) { // make asynchronous API call // and return appropriate result } }

Page 44: Practical Protocols with Associated Types

protocol Gettable { func get(completionHandler: Result<[Food]> -> Void) }

Page 45: Practical Protocols with Associated Types

protocol Gettable { associatedtype T func get(completionHandler: Result<T> -> Void) }

Page 46: Practical Protocols with Associated Types

struct FoodService: Gettable { func get(completionHandler: Result<[Food]> -> Void) { // make asynchronous API call // and return appropriate result } }

Page 47: Practical Protocols with Associated Types

// NYCFoodViewController

override func viewDidLoad() { super.viewDidLoad() getFood(fromService: FoodService()) }

func getFood<S: Gettable where S.T == [Food]>(fromService service: S) { service.get() { [weak self] result in switch result { case .Success(let food): self?.dataSource = food case .Failure(let error): self?.showError(error) } } }

Page 48: Practical Protocols with Associated Types

// NYCFoodViewControllerTests

class Fake_FoodService: Gettable { var getWasCalled = false func get(completionHandler: Result<[Food]> -> Void) { getWasCalled = true completionHandler(Result.Success(food)) } }

Page 49: Practical Protocols with Associated Types

// NYCFoodViewControllerTests

func testFetchFood() { let fakeFoodService = Fake_FoodService() viewController.getFood(fromService: fakeFoodService) XCTAssertTrue(fakeFoodService.getWasCalled) XCTAssertEqual(viewController.dataSource.count, food.count) XCTAssertEqual(viewController.dataSource, food) }

Page 50: Practical Protocols with Associated Types
Page 51: Practical Protocols with Associated Types
Page 52: Practical Protocols with Associated Types
Page 53: Practical Protocols with Associated Types
Page 54: Practical Protocols with Associated Types
Page 55: Practical Protocols with Associated Types
Page 56: Practical Protocols with Associated Types
Page 57: Practical Protocols with Associated Types
Page 58: Practical Protocols with Associated Types
Page 59: Practical Protocols with Associated Types

T H A N K Y O U !

• @NatashaTheRobot

• @NatashaTheNomad

• This Week in Swift Newsletter

• @tryswiftnyc 🐥🗽🎉

• BROOKLYNSWIFT - 20% OFF

• Volunteers 🙋