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

Functional Reactive Programming - RxSwift

Functional Reactive Programming - RxSwift

Understand the basics: what reactive programming is, how it works why you should use it. Check how RXSwift library achieves FRP and a declarative way programming!

Avatar for Rodrigo Freitas

Rodrigo Freitas

November 21, 2016

Other Decks in Programming

Transcript

  1. Rx.N et Rx.JS Rx.Java Rx.C pp Rx.Ruby Rx.Scala, RxC losure

    Rx.Py, RxPH P Rx.Kotlin Rx.Sw ift Reactive Extensions nov. 2009 mar. 2010 mar. 2012 nov. 2012 dec. 2012 jan. 2013 mar. 2013 out. 2013 feb. 2015
  2. Observable Life cycle observable sequence marble diagrams // Terminate normally

    // Terminate with error // Endless sequence 1 2 3 tap tap tap tap a b
  3. Observable Emits events over time protocol Observable { associatedtype E

    func on(_ event: Event<E>) } enum Event<Element: Any> { case Next(Any) case Error(Error) case Completed }
  4. Observable Listen Operator let observable = Observable.just("Hello World") // next(Hello

    World) // completed observable.subscribe(onNext: { (value) in print(value) // Pump out an element }, onError: { (error) in // Catch error }, onCompleted: { // Catch completed }, onDisposed: { // Dispose the subscription })
  5. Observable Create Operator let disposeBag = DisposeBag() Observable.from(["", "", "",

    ""]) .subscribe(onNext: { print($0) }) .addDisposableTo(disposeBag)
  6. Observable Create Operator let disposeBag = DisposeBag() Observable.from(["", "", "",

    ""]) .subscribe(onNext: { print($0) }) .addDisposableTo(disposeBag) // // // //
  7. Observable Transforming Operators let disposeBag = DisposeBag() Observable.of(2, 3, 4)

    .map { $0 * $0 } .subscribe(onNext: { print($0) }) .addDisposableTo(disposeBag)
  8. Observable let disposeBag = DisposeBag() Observable.of(2, 3, 4) .map {

    $0 * $0 } .subscribe(onNext: { print($0) }) .addDisposableTo(disposeBag) 4 16 2 4 3 9 map { $0 * $0 } Transforming Operators
  9. class ElementViewController: UIViewController { @IBOutlet weak var usernameTextField: UITextField! @IBOutlet

    weak var passwordTextField: UITextField! @IBOutlet weak var button: UIButton! override func viewDidLoad() { button.isEnabled = false usernameTextField.delegate = self passwordTextField.delegate = self } func enableLoginButton(username: String, password: String) { button.isEnabled = (username != "" && password != "") } } extension ElementViewController: UITextFieldDelegate { func textFieldShouldEndEditing(_ textField: UITextField) -> Bool { // check textfield } func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { // check textfield return true }
  10. class ElementViewController: UIViewController { @IBOutlet weak var usernameTextField: UITextField! @IBOutlet

    weak var passwordTextField: UITextField! @IBOutlet weak var button: UIButton! let disposeBag = DisposeBag() override func viewDidLoad() { super.viewDidLoad() Observable.combineLatest(usernameTextField.rx.text, passwordTextField.rx.text) { username, password in return username != "" && password != "" } .subscribe { button.isEnable = $0 } .addDisposableTo(disposeBag) } }
  11. class ElementViewController: UIViewController { @IBOutlet weak var usernameTextField: UITextField! @IBOutlet

    weak var passwordTextField: UITextField! @IBOutlet weak var button: UIButton! let disposeBag = DisposeBag() override func viewDidLoad() { super.viewDidLoad() Observable.combineLatest(usernameTextField.rx.text, passwordTextField.rx.text) { username, password in return username != "" && password != "" } .subscribe { button.isEnable = true } .addDisposableTo(disposeBag) } } class ElementViewController: UIViewController { @IBOutlet weak var usernameTextField: UITextField! @IBOutlet weak var passwordTextField: UITextField! @IBOutlet weak var button: UIButton! override func viewDidLoad() { button.isEnabled = false usernameTextField.delegate = self passwordTextField.delegate = self } func enableLoginButton(username: String, password: String) { button.isEnabled = (username != "" && password != "") } } extension ElementViewController: UITextFieldDelegate { func textFieldShouldEndEditing(_ textField: UITextField) -> Bool { // check textfield } func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { // check textfield return true } 40% Saving Traditional Reactive
  12. Senquence API Calls 1. Get userID 2. Get credit card

    account ID 3. Get credit card info
  13. Alamofire.request("https://fake/login", method: .post) .responseJSON { (response) in Alamofire.request("https://fake/creaditToken", method: .post,

    parameters: ["creditToken": response.id]) .responseJSON { (response) in Alamofire.request("https//fake/creaditCard", method: .post, parameters: ["creditCard": response.token]) .responseJSON { // get credit card info } } }
  14. class CreditCardService { func getCreditCards() { let service = []

    as! Service service.rxLogin(username: "[email protected]", password: "12345") .flatMap { (authResponse) -> Observable<CreditCardAccount> in return service.rxCredidCardAccount(userId: authResponse.userId) } .flatMap { (creditCardAccount) -> Observable<[CreditCardInfo]> in return service.rxAllCreditCards(userId: creditCardAccount.cardsId) } .subscribe { (creditCardInfo) in print(creditCardInfo) } } }
  15. static func request(endpoint: Resource) -> Observable<[String:AnyObject]> { return Observable.create {

    observer in } return Disposables.create { request.cancel() } } } Request Observable
  16. let request = Alamofire.request(endpoint.path, method: endpoint.method, parameters: endpoint.parameter) .validate() .responseJSON

    { (response: DataResponse<Any>) in if let err = response.result.error { observer.onError(err) } else { if let result = response.result.value as? [String:AnyObject] { observer.onNext(result) } observer.onCompleted() } static func request(endpoint: Resource) -> Observable<[String:AnyObject]> { return Observable.create { observer in } return Disposables.create { request.cancel() } } } Request Observable
  17. @IBOutlet weak var searchBar: UISearchBar! @IBOutlet weak var tableView: UITableView!

    // Trigger when reach the bottom of the tableView let trigger = tableView.rx.contentOffset.flatMap { _ in (self.tableView.contentOffset.y + self.tableView.frame.size.height + 20 > self.tableView.contentSize.height) ? Observable.just() : Observable.empty() } let searchResult = searchBar.rx.text.asObservable() .debounce(3, scheduler: MainScheduler.instance) .flatMapLatest { query -> Observable<[Character]> in return CharacterAPI().heros(search: query!, trigger: trigger) }.catchErrorJustReturn([Character]()) searchResult.bindTo(tableView.rx.items(cellIdentifier: "HERO_CELL")) { row, character, herocell in let cell: HeroTableViewCell = (herocell as? HeroTableViewCell)! cell.heroNameLabel.text = character.name cell.downloadableImage = UIImage.imageFrom(urlString: character.getHeroImagePath()) }.addDisposableTo(disposeBag) ViewController