1. subscribe, bind, drive 특징 비교
|
subscribe |
bind |
drive |
사용 대상 |
Observable |
Observable, Driver |
Driver |
에러 처리 |
에러를 처리 가능 |
에러 처리하지 않음 |
에러 처리하지 않음 |
Thread 관리 |
별도의 Thread 관리가 필요 (Main Thread에서 동작하지 않음) |
Main Thread에서 자동으로 동작 |
Main Thread에서 자동으로 동작 |
주요 사용 사례 |
모든 Observable에서 값을 직접 처리할 때 |
주로 UI 바인딩에 사용, UI 요소와 데이터를 연결 |
UI 바인딩에 최적화된 Driver 사용 시 |
주요 이벤트 |
next, completed, error |
next (에러 이벤트는 전달되지 않음) |
next (에러 이벤트는 전달되지 않음) |
Hot/Cold Observable |
Cold/Hot Observable 모두 처리 가능 |
Cold/Hot Observable 모두 처리 가능 |
Hot Observable인 Driver만 사용 가능 |
메모리 관리 |
disposed(by:) 또는 직접 해제 필요 |
disposed(by:)를 통해 메모리 관리 |
disposed(by:)를 통해 메모리 관리 |
2. 사용 예시
subscribe 예시
import RxSwift
let observable = Observable.of(1, 2, 3, 4, 5)
let disposeBag = DisposeBag()
observable.subscribe(
onNext: { value in
print("Next:", value)
},
onError: { error in
print("Error:", error)
},
onCompleted: {
print("Completed")
}
).disposed(by: disposeBag)
- subscribe는 next, error, completed 이벤트를 모두 처리할 수 있음.
bind 예시
import UIKit
import RxSwift
import RxCocoa
class ViewController: UIViewController {
let disposeBag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
let textField = UITextField()
let label = UILabel()
textField.rx.text.orEmpty.bind(to: label.rx.text).disposed(by: disposeBag)
}
}
- bind는 Observable을 UI 요소에 직접 연결하여 UI 업데이트를 안전하게 수행.
- 에러 처리가 필요 없는 UI 작업에서 유용.
drive 예시
import UIKit
import RxSwift
import RxCocoa
class ViewController: UIViewController {
let disposeBag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
let textField = UITextField()
let label = UILabel()
textField.rx.text.orEmpty.asDriver().drive(label.rx.text).disposed(by: disposeBag)
}
}
- drive는 Driver를 사용하여 UI 요소와의 바인딩을 안전하게 수행.
- 에러를 전파하지 않고, Main Thread에서 동작하기 때문에 UI 업데이트에 최적화.
3. 선택 가이드
- subscribe
- 에러 이벤트 처리가 필요한 경우 사용.
- 예를 들어, 네트워크 요청이나 파일 처리 등의 작업에서 발생하는 에러를 직접 처리해야 할 때 적합.
- Observable 시퀀스의 모든 이벤트(next, error, completed)를 처리할 수 있음.
- bind
- UI 요소와 Observable을 간단하게 바인딩하고자 할 때 사용.
- 에러 처리가 필요 없고, Main Thread에서 동작하는 UI 바인딩에 적합.
- 에러가 발생해도 작업을 계속 진행해야 할 때 유용.
- drive
- UI 바인딩에 최적화된 Driver를 사용할 때 적합.
- Driver는 Hot Observable이므로, 여러 구독자가 동일한 데이터를 공유할 때 유리 (스트림 공유).
- 에러 전파 없이 Main Thread에서 안전하게 동작하는 UI 작업에 적합.
4. 정리
subscribe |
모든 Observable에서 사용 가능, next, error, completed 이벤트를 처리할 수 있음. 에러 처리가 필요할 때 사용 |
bind |
Observable 및 Driver와 UI 요소를 간단히 바인딩, 에러를 처리하지 않으며 Main Thread에서 동작 |
drive |
Driver에서만 사용 가능, Main Thread에서 안전하게 동작, 에러 처리 없이 UI 작업에 최적화 |
(+) bind와 dirve는 도대체 어떤 차이?
bind는 Main Thread에서 동작하지만, 스트림을 공유하지는 않음.
만약 bind를 사용하면서 스트림도 공유하고 싶다면 share 연산자를 사용해야 함.
func bindTest() {
let tap = signInButton.rx.tap
.map { "test \\(Int.random(in: 1...100))" }
tap.bind(to: emailTextField.rx.text)
.disposed(by: disposeBag)
tap.bind(to: passwordTextField.rx.text)
.disposed(by: disposeBag)
tap.bind(to: nicknameTextField.rx.text)
.disposed(by: disposeBag)
let sharedTap = signInButton.rx.tap
.map { "test \\(Int.random(in: 1...100))" }
.share()
sharedTap.bind(to: emailTextField.rx.text)
.disposed(by: disposeBag)
sharedTap.bind(to: passwordTextField.rx.text)
.disposed(by: disposeBag)
sharedTap.bind(to: nicknameTextField.rx.text)
.disposed(by: disposeBag)
}
하지만, drive는 Main Thread에서 동작하면서, 스트림을 공유.
만약 bind를 사용하면서 스트림도 공유하고 싶다면 share 연산자를 사용해야 함.
func driveTest() {
let tap = signInButton.rx.tap
.map { "test \\(Int.random(in: 1...100))" }
.asDriver(onErrorJustReturn: "")
tap.drive(emailTextField.rx.text)
.disposed(by: disposeBag)
tap.drive(passwordTextField.rx.text)
.disposed(by: disposeBag)
tap.drive(nicknameTextField.rx.text)
.disposed(by: disposeBag)
}