Upgrade to Pro — share decks privately, control downloads, hide ads and more …

The Road To Damascus, or FRP and Me

F28c4835c9e2277b6e04b86574532a2d?s=47 Abizer Nasir
September 14, 2017

The Road To Damascus, or FRP and Me

Presentation I gave at NSSpain 2017 about my thoughts on Functional Reactive Program and whether I should use it.


Abizer Nasir

September 14, 2017


  1. The Road to Damascus or, FRP and me Abizer Nasir

    | @abizern | abizern.org
  2. I like to keep things simple • MVC • Dependency

    Injection, protocols, value types • Storyboards • Core Data
  3. Functional Reactive Programming • Reactive: Treats data as a flow

    over time rather than individual events. A sequence. • Functional: map and filter and reduce can be applied to these sequences - the things we like about Swift
  4. Choices • RxSwift • ReactiveCocoa • PromiseKit • ReSwift

  5. Functional Reactive Programming (FRP) is not a solution for Massive

    View Controllers.
  6. Not a good starting point “The RepositoryListViewController is also a

    delegate and a data source for the table view. It handles the navigation, formats model data to display and performs network requests. Wow, a lot of responsibilities for just one View Controller!”
  7. FRP is not just a wrapper around KVO

  8. FRP “flattens” asynchronous code — Me.

  9. An Observable is a sequence of events.

  10. Events only have three states public enum Event<Element> { case

    next(Element) case error(Swift.Error) case completed }
  11. Events are emitted when an Observable is subscribed to Think

    of subscribing as repeatedly calling next() an an Iterator.
  12. None
  13. RxMarbles.com

  14. RxMarbles.com

  15. RxMarbles.com

  16. RxMarbles.com

  17. RxMarbles.com

  18. “Flattens Asynchronous Code” By that I mean they are treated

    as the same thing. • A single value injected into a View Controller • The text in a Text View • The response from a network request.
  19. Validate UserName & Password, Classic final class ViewController: UIViewController {

    @IBOutlet private var name: UITextField! { didSet { name.addTarget(self, action: #selector(validate(_:)), for: .editingChanged) } } @IBOutlet private var password: UITextField!{ didSet { password.addTarget(self, action: #selector(validate(_:)), for: .editingChanged)} } @IBOutlet private var confirm: UIButton! @objc private func validate(_ sender: UITextField) { let name = self.name.text ?? "" let password = self.password.text ?? "" confirm.isEnabled = !name.isEmpty && !password.isEmpty } }
  20. Validate UserName & Password, RxSwift class LoginViewController: UIViewController { @IBOutlet

    private var name: UITextField! @IBOutlet private var password: UITextField! @IBOutlet private var confirm: UIButton! let disposeBag = DisposeBag() override func viewDidLoad() { super.viewDidLoad() let username = name.rx.text.orEmpty.asObservable() let password = password.rx.text.orEmpty.asObservable() confirmButtonValid(username: username, password: password) .bind(to: confirmButton.rx.isEnabled) .disposed(by: disposeBag) } func confirmButtonValid(username: Observable<String>, password: Observable<String>) -> Observable<Bool> { return Observable.combineLatest(username, password { (username, password) in return !username.isEmpty && !password.isEmpty } } }
  21. func confirmButtonValid(username: Observable<String>, password: Observable<String>) -> Observable<Bool> { return Observable.combineLatest(username,

    password { (username, password) in return !username.isEmpty && !password.isEmpty } }
  22. Observable<Bool> can be - .next(Bool) - .error(Error) - .completed Looks

    a lot like Result<Bool, Error> - .success(Bool) - .failure(Error)
  23. Composition searchBar.rx.text .orEmpty .filter { $0.characters.count > 3 } .debounce

    { 0.5, scheduler: MainScheduler.instance } .map { query in let url = URLBuilder.urlFor(query) return URLRequest(url: url) .flatMapLatest{ request in return URLSession.shared.rx.json(request: request) .catchErrorJustReturn([]) } .map { json -> [Model] in guard let items = json as? [[String: Any]] else { return [] } return items.flatMap { Model.init } } .bindTo(tableView.rx.items) { tableView, row, model in let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") cell.configureWith(model) return cell } .disposed(by: disposeBag) h/t Marin Todorov @icanzilb
  24. The code is in one place. It is readable, the

    order is determined and easy to reason about.
  25. Magic? • Not really. The code is still there. •

    Boilerplate is hidden away
  26. It’s a Big DSL • RxSwift for FRP • RxBindings

    for working with UI elements • RxTest
  27. It’s a Large Dependency • Active project with many contributors

    and users. • Easily installed with CocoaPods or Carthage, but these are the days of Xcode transitions. • You don’t have to use it everywhere, but if you’ve added it...
  28. Where Am I on the road? Well, I’m still on

  29. RxSwift https://store.raywenderlich.com/ products/rxswift

  30. Thank You ! Abizer Nasir | @abizern | abizern.org