[RxSwift] RxCocoa Basics

Posted by Sung Kyungmo on February 12, 2020

RxCocoa

  • Cocoa Framework에 Reactive의 장점을 더해주는 라이브러리

Install

1
2
3
4
5
6
# Podfile
use_frameworks!

target 'YOUR_TARGET_NAME' do
    pod 'RxCocoa'
end

Cocoa Touch

1
2
3
4
5
@IBOutlet weak var valueLabel: UILabel!
   
@IBAction func onTap(_ sender: Any) {
    valueLabel.text = "Hello, Cocoa Touch"
}

RxCocoa

1
2
3
4
5
6
7
8
9
10
11
12
13
14
let disposeBag = DisposeBag()
    
@IBOutlet weak var valueLabel: UILabel!
    
@IBOutlet weak var tapButton: UIButton!
    
override func viewDidLoad() {
    super.viewDidLoad()
      
    tapButton.rx.tap
        .map{ "Hello, RxCocoa" }
        .bind(to: valueLabel.rx.text)
        .disposed(by: disposeBag)
}

Binding

  • Observable 타입을 채용한 모든 형식이 생산자(Producer)
  • Label 이나 ImageView 같은 UI 컴포넌트는 소비자(Consumer)
  • 생산자가 생산한 데이터는 소비자한테 전달되고 소비자는 적절한 방법으로 데이터를 사용함
  • Binder는 UI Binding에 사용되는 특별한 Observer로 데이터 소비자의 역할을 수행
  • Binder는 Error 이벤트를 받지 않고 Next, Completed 이벤트만 전달
  • Main Thread 에서 실행되는것을 보장

    Cocoa Touch

  • Delegate 패턴을 구현해야함
  • 최종 문자열을 조합하는 코드 필요
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    
    class BindingCocoaTouchViewController: UIViewController {
       @IBOutlet weak var valueLabel: UILabel!
       @IBOutlet weak var valueField: UITextField!
         
       override func viewDidLoad() {
          super.viewDidLoad()
            
          valueLabel.text = ""
          valueField.delegate = self
          valueField.becomeFirstResponder()
       }
         
       override func viewWillDisappear(_ animated: Bool) {
          super.viewWillDisappear(animated)
            
          valueField.resignFirstResponder()
       }
    }
      
    extension BindingCocoaTouchViewController: UITextFieldDelegate {
       func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
          guard let currentText = textField.text else {
             return true
          }
            
          let finalText = (currentText as NSString).replacingCharacters(in: range, with: string)
          valueLabel.text = finalText
            
          return true
       }
    }
    


    RxCocoa

  • 코드가 간결해짐
  • 최종 문자열을 조합하는 코드 필요 없음
  • Delegate 패턴을 구현할 필요가 없어 데이터 흐름을 쉽게 파악 가능
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    
    class BindingRxCocoaViewController: UIViewController {
      @IBOutlet weak var valueLabel: UILabel!
      @IBOutlet weak var valueField: UITextField!
      
      let disposeBag = DisposeBag()
      
      override func viewDidLoad() {
        super.viewDidLoad()
      
        valueLabel.text = ""
        valueField.becomeFirstResponder()
      
    //    valueField.rx.text
    //      .observeOn(MainScheduler.instance) //메인 스레드에서 실행해야함
    //      .subscribe(onNext: { [weak self] str in
    //        self?.valueLabel.text = str
    //      })
    //      .disposed(by: disposeBag)
      
        //Main Thread 실행을 보장하는 bind를 통해 간결하게 구현 가능
        valueField.rx.text
          .bind(to: valueLabel.rx.text)
          .disposed(by: disposeBag)
      }
      
      override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
      
        valueField.resignFirstResponder()
      }
    }
    

Reference


http://reactivex.io/
https://kxcoding.com/