
(1)편
https://velog.io/@maddie/iOS-RxSwift%EA%B0%80-%EB%AD%98%EA%B9%8C
지난 글에서 RxSwift에 대해 알아보았다.
오늘은 RxSwift에서 이벤트를 주고 받는 Observable과 Observer를 지정하는 방식인 Subscribe과 Bind의 차이에 대해 알아보자!
만약에 버튼을 눌러 네트워크 통신을 받아오는 로직을 구현해야 한다고 가정해보자. 또 무시무시한 보라색 에러를 만나고 싶지 않으면 UI 관련 로직은 메인 스레드한테 시켜야 한다.
이 간단한 로직을 여러 방법으로 구현해보면서 차이를 알아보자!
우선 원래 알던대로 subscribe + 메인 스레드를 활용해서 구현해보면 다음과 같이 나타낼 수 있다.
button.rx.tap
.subscribe { [weak self] _ in
guard let self = self else { return }
DispatchQueue.main.async { // 네트워크 통신이 있다고 가정!
self.label.text = "Tapped"
self.textField.text = "Tapped"
}
}.disposed(by: bag)
요렇게 하면 메인스레드한테 비동기로 일하라고 시키는 로직이 되겠다.
그런데, Rx에는 Swift의 DispatchQueue와 똑같은 기능을 하는 Scheduler가 있다.
button.rx.tap
.observe(on: MainScheduler.instance) // 메인 스레드에서!
.subscribe { [weak self] _ in
guard let self = self else { return }
self.label.text = "Tapped"
self.textField.text = "Tapped"
}.disposed(by: bag)
요렇게 Subscribe로 Observable과 Observer를 연결해주고,
일은 메인스레드에서 시키라고 MainScheduler를 부른다!
1번과 2번은 순환참조를 막기 위해 weak self처리를 해줘야 메모리 누수를 예방할 수 있다.
button.rx.tap
.observe(on: MainScheduler.instance)
.subscribe(with: self) { owner, _ in
owner.label.text = "Tapped"
owner.textField.text = "Tapped"
}
.disposed(by: bag)
with 키워드: 내부에서 weak self + Optional Binding 처리를 해준다!
button.rx.tap
.bind(with: self) { owner, _ in
owner.label.text = "Tapped"
owner.textField.text = "Tapped"
}
.disposed(by: bag)
드디어 모습을 드러낸 오늘의 주인공 ! 🐶
bind는 메인스레드에서 동작한다. 그래서 위에서 subscribe랑 썼던 MainScheduler 필요 없다!
따라서 bind 키워드는 메인스레드 동작 + Next 이벤트에 대한 처리만 담당한다.
button.rx.tap
.map { "Tapped" }
.bind(to: label.rx.text, textField.rx.text)
.disposed(by: bag)
map: Observable이 방출하는 값을 변환한다. 여기서는 버튼이 클릭될 때마다 발생하는 이벤트를 "Tapped"라는 문자열로 변환!
4번과의 차이는, 4번은 bind(with:)를 사용하여 직접 코드를 작성하여 UI 요소의 속성을 업데이트했다면, 5번은 bind(to:)를 사용하여 Observable의 값을 UI 요소의 속성에 직접 바인딩!!
여러번 자주 써보면서, 용도와 차이점을 아는 게 중요하겠다!