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. 2.

    I like to keep things simple • MVC • Dependency

    Injection, protocols, value types • Storyboards • Core Data
  2. 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
  3. 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!”
  4. 10.

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

    next(Element) case error(Swift.Error) case completed }
  5. 11.

    Events are emitted when an Observable is subscribed to Think

    of subscribing as repeatedly calling next() an an Iterator.
  6. 12.
  7. 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.
  8. 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 = ?? "" let password = self.password.text ?? "" confirm.isEnabled = !name.isEmpty && !password.isEmpty } }
  9. 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 } } }
  10. 22.

    Observable<Bool> can be - .next(Bool) - .error(Error) - .completed Looks

    a lot like Result<Bool, Error> - .success(Bool) - .failure(Error)
  11. 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
  12. 24.

    The code is in one place. It is readable, the

    order is determined and easy to reason about.
  13. 26.

    It’s a Big DSL • RxSwift for FRP • RxBindings

    for working with UI elements • RxTest
  14. 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...