O slideshow foi denunciado.
Seu SlideShare está sendo baixado. ×

Practical Protocol-Oriented-Programming

Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Próximos SlideShares
An Introduction to Redux
An Introduction to Redux
Carregando em…3
×

Confira estes a seguir

1 de 66 Anúncio

Practical Protocol-Oriented-Programming

Baixar para ler offline

Value types are at the core of Swift (seriously, mostly everything in the Swift standard library is a value type). But how do you avoid subclassing? That’s where the power of Protocol-Oriented programming comes in. Learn how to structure your code to never subclass (almost) again! Practical everyday examples and ideas for your own code base will be included.

Value types are at the core of Swift (seriously, mostly everything in the Swift standard library is a value type). But how do you avoid subclassing? That’s where the power of Protocol-Oriented programming comes in. Learn how to structure your code to never subclass (almost) again! Practical everyday examples and ideas for your own code base will be included.

Anúncio
Anúncio

Mais Conteúdo rRelacionado

Diapositivos para si (20)

Semelhante a Practical Protocol-Oriented-Programming (20)

Anúncio

Mais de Natasha Murashev (20)

Mais recentes (20)

Anúncio

Practical Protocol-Oriented-Programming

  1. @NatashaTheRobot
  2. Protocol-Oriented Programming in Swift Dave Abrahams Professor of Blowing-Your-Mind
  3. –- Professor of Blowing-Your-Mind "Swift Is a Protocol-Oriented Programming Language"
  4. Practical POP • View • (UITable)ViewController • Networking
  5. POP Views
  6. // FoodImageView.swift import UIKit class FoodImageView: UIImageView { func shake() { let animation = CABasicAnimation(keyPath: "position") animation.duration = 0.05 animation.repeatCount = 5 animation.autoreverses = true animation.fromValue = NSValue(CGPoint: CGPointMake(self.center.x - 4.0, self.center.y)) animation.toValue = NSValue(CGPoint: CGPointMake(self.center.x + 4.0, self.center.y)) layer.addAnimation(animation, forKey: "position") } }
  7. // ViewController.swift import UIKit class ViewController: UIViewController { @IBOutlet weak var foodImageView: FoodImageView! @IBAction func onShakeButtonTap(sender: AnyObject) { foodImageView.shake() } }
  8. 💃💃💃
  9. // ShakeableButton.swift import UIKit class ActionButton: UIButton { func shake() { let animation = CABasicAnimation(keyPath: "position") animation.duration = 0.05 animation.repeatCount = 5 animation.autoreverses = true animation.fromValue = NSValue(CGPoint: CGPointMake(self.center.x - 4.0, self.center.y)) animation.toValue = NSValue(CGPoint: CGPointMake(self.center.x + 4.0, self.center.y)) layer.addAnimation(animation, forKey: "position") } }
  10. // ViewController.swift class ViewController: UIViewController { @IBOutlet weak var foodImageView: FoodImageView! @IBOutlet weak var actionButton: ActionButton! @IBAction func onShakeButtonTap(sender: AnyObject) { foodImageView.shake() actionButton.shake() } }
  11. 🤔
  12. // UIViewExtension.swift import UIKit extension UIView { func shake() { let animation = CABasicAnimation(keyPath: "position") animation.duration = 0.05 animation.repeatCount = 5 animation.autoreverses = true animation.fromValue = NSValue(CGPoint: CGPointMake(self.center.x - 4.0, self.center.y)) animation.toValue = NSValue(CGPoint: CGPointMake(self.center.x + 4.0, self.center.y)) layer.addAnimation(animation, forKey: "position") } }
  13. class FoodImageView: UIImageView { // other customization here } class ActionButton: UIButton { // other customization here } class ViewController: UIViewController { @IBOutlet weak var foodImageView: FoodImageView! @IBOutlet weak var actionButton: ActionButton! @IBAction func onShakeButtonTap(sender: AnyObject) { foodImageView.shake() actionButton.shake() } }
  14. // Shakeable.swift import UIKit protocol Shakeable { } extension Shakeable where Self: UIView { func shake() { // implementation code } }
  15. class FoodImageView: UIImageView, Shakeable { } class ActionButton: UIButton, Shakeable { }
  16. class FoodImageView: UIImageView, Shakeable, Dimmable { }
  17. class FoodImageView: UIImageView, Dimmable { }
  18. Transparent View Controllers and Dim Backgrounds totem.training
  19. 👯👯👯👯👯
  20. POP (UITable)ViewControllers
  21. // FoodLaLaViewController override func viewDidLoad() { super.viewDidLoad() let foodCellNib = UINib(nibName: "FoodTableViewCell", bundle: nil) tableView.registerNib(foodCellNib, forCellReuseIdentifier: "FoodTableViewCell") }
  22. let foodCellNib = UINib(nibName: String(FoodTableViewCell), bundle: nil) tableView.registerNib(foodCellNib, forCellReuseIdentifier: String(FoodTableViewCell))
  23. protocol ReusableView: class {} extension ReusableView where Self: UIView { static var reuseIdentifier: String { return String(self) } }
  24. extension UITableViewCell: ReusableView { } FoodTableViewCell.reuseIdentifier // FoodTableViewCell
  25. let foodCellNib = UINib(nibName: "FoodTableViewCell", bundle: nil) tableView.registerNib(foodCellNib, forCellReuseIdentifier: FoodTableViewCell.reuseIdentifier)
  26. protocol NibLoadableView: class { } extension NibLoadableView where Self: UIView { static var nibName: String { return String(self) } }
  27. extension FoodTableViewCell: NibLoadableView { } FoodTableViewCell.nibName // "FoodTableViewCell"
  28. let foodCellNib = UINib(nibName: FoodTableViewCell.nibName, bundle: nil) tableView.registerNib(foodCellNib, forCellReuseIdentifier: FoodTableViewCell.reuseIdentifier)
  29. extension UITableView { func register<T: UITableViewCell where T: ReusableView, T: NibLoadableView>(_: T.Type) { let nib = UINib(nibName: T.nibName, bundle: nil) registerNib(nib, forCellReuseIdentifier: T.reuseIdentifier) } }
  30. let foodCellNib = UINib(nibName: "FoodTableViewCell", bundle: nil) tableView.registerNib(foodCellNib, forCellReuseIdentifier: "FoodTableViewCell")
  31. tableView.register(FoodTableViewCell)
  32. extension UITableView { func dequeueReusableCell<T: UITableViewCell where T: ReusableView>(forIndexPath indexPath: NSIndexPath) -> T { guard let cell = dequeueReusableCellWithIdentifier(T.reuseIdentifier, forIndexPath: indexPath) as? T else { fatalError("Could not dequeue cell with identifier: (T.reuseIdentifier)") } return cell } }
  33. guard let cell = tableView.dequeueReusableCellWithIdentifier(“FoodTableViewCell", forIndexPath: indexPath) as? FoodTableViewCell else { fatalError("Could not dequeue cell with identifier: FoodTableViewCell") }
  34. let cell = tableView.dequeueReusableCell(forIndexPath: indexPath) as FoodTableViewCell
  35. if indexPath.row == 0 { return tableView.dequeueReusableCell(forIndexPath: indexPath) as DesertTableViewCell } return tableView.dequeueReusableCell(forIndexPath: indexPath) as FoodTableViewCell
  36. iOS Cell Registration & Reusing with Swift Protocol Extensions and Generics medium.com/@gonzalezreal
  37. Protocol-Oriented Segue Identifiers in Swift natashatherobot.com
  38. POP Networking
  39. struct FoodService { func get(completionHandler: Result<[Food]> -> Void) { // make asynchronous API call // and return appropriate result } }
  40. enum Result<T> { case Success(T) case Failure(ErrorType) }
  41. struct FoodService { func get(completionHandler: Result<[Food]> -> Void) { // make asynchronous API call // and return appropriate result } }
  42. // FoodLaLaViewController var dataSource = [Food]() { didSet { tableView.reloadData() } } override func viewDidLoad() { super.viewDidLoad() getFood() } private func getFood() { FoodService().getFood() { [weak self] result in switch result { case .Success(let food): self?.dataSource = food case .Failure(let error): self?.showError(error) } } }
  43. View Controller Tests?!!! 😱
  44. // FoodLaLaViewController var dataSource = [Food]() { didSet { tableView.reloadData() } } override func viewDidLoad() { super.viewDidLoad() getFood() } private func getFood() { FoodService().getFood() { [weak self] result in switch result { case .Success(let food): self?.dataSource = food case .Failure(let error): self?.showError(error) } } }
  45. // FoodLaLaViewController func getFood(fromService service: FoodService) { service.getFood() { [weak self] result in // handle result } }
  46. // FoodLaLaViewControllerTests func testFetchFood() { viewController.getFood(fromService: FoodService()) // 🤔 now what? }
  47. struct FoodService { func get(completionHandler: Result<[Food]> -> Void) { // make asynchronous API call // and return appropriate result } }
  48. protocol Gettable { associatedtype T func get(completionHandler: Result<T> -> Void) }
  49. struct FoodService: Gettable { func get(completionHandler: Result<[Food]> -> Void) { // make asynchronous API call // and return appropriate result } }
  50. // FoodLaLaViewController 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) } } }
  51. // FoodLaLaViewControllerTests class Fake_FoodService: Gettable { var getWasCalled = false func get(completionHandler: Result<[Food]> -> Void) { getWasCalled = true completionHandler(Result.Success(food)) } }
  52. // FoodLaLaViewControllerTests func testFetchFood() { let fakeFoodService = Fake_FoodService() viewController.getFood(fromService: fakeFoodService) XCTAssertTrue(fakeFoodService.getWasCalled) XCTAssertEqual(viewController.dataSource.count, food.count) XCTAssertEqual(viewController.dataSource, food) }
  53. Update: View Controller Data Injection with Storyboards and Segues in Swift natashatherobot.com
  54. Protocols with Associated Types Alexis Gallagher 2015.funswiftconf.com
  55. 😎😎😎
  56. Practical POP • View • (UITable)ViewController • Networking
  57. Beyond Crusty: Real-World Protocols Rob Napier thedotpost.com
  58. Blending Cultures: The Best of Functional, Protocol-Oriented, and Object-Oriented Programming Daniel Steinberg realm.io
  59. @NatashaTheRobot

×