Scheduler
는 RxSwift에서 작업이 실행되는 스레드나 큐를 관리하는 역할을 한다.
Observable 구독을 통해서 UI 작업을 처리하게 되었다면, 그 작업이 메인 스레드에서 동작하도록 명시하는 것이 좋다.
( “UI 작업은 메인 스레드에서 이루어져아한다” → iOS 앱 개발의 기본 개념 )
Observable.just("Hello")
.observeOn(MainScheduler.instance)
.subscribe(onNext: { value in
print(value) // UI 업데이트
})
let scheduler = ConcurrentDispatchQueueScheduler(qos: .background)
Observable.just("Background Task")
.subscribeOn(scheduler)
.observeOn(MainScheduler.instance)
.subscribe(onNext: { value in
print(value)
})
userInteractive
(최고 우선순위 - e.g. UI 업데이트 ,애니메이션)userInitiated
(높은 우선순위 - e.g. 버튼 클릭 후 데이터 로딩)default
(기본 우선순위 - e.g. 일반적인 백그라운드 작업)utility
(낮은 우선순위 - e.g. 데이터 다운로드, 백업)background
(최저 우선순위 - e.g. 대용량 데이터 정리, 동기화)unspecified
(시스템 결정 - 어떤 우선순위로 처리해도 상관없는 작업)let queue = DispatchQueue(label: "com.example.serial")
let scheduler = SerialDispatchQueueScheduler(queue: queue, internalSerialQueueName: "serialQueue")
Observable.of(1, 2, 3)
.subscribeOn(scheduler)
.subscribe(onNext: { value in
print(value)
})
subscribeOn
& observeOn
subscribeOn
: Observable이 구독될 때 사용할 스레드를 지정한다. observeOn
: Observable이 방출하는 이벤트를 처리할 스레드를 지정한다.https://reactivex.io/documentation/scheduler.html |
---|
예제:
Observable.of(1, 2, 3)
.subscribeOn(ConcurrentDispatchQueueScheduler(qos: .background)) // Observable 생성 시 백그라운드 스레드 사용
.observeOn(MainScheduler.instance) // UI 업데이트는 메인 스레드에서 실행
.subscribe(onNext: { value in
print(value)
})
Subject
는 Observable과 Observer의 역할을 동시에 하는 특별한 타입이다.
https://reactivex.io/documentation/subject.html |
---|
let subject = BehaviorSubject(value: "Initial Value")
subject.onNext("Second Value")
subject.subscribe(onNext: { value in
print(value)
})
https://reactivex.io/documentation/subject.html |
---|
let subject = PublishSubject<String>()
subject.onNext("Ignored")
subject.subscribe(onNext: { value in
print(value)
})
subject.onNext("Emitted")
Relay는 RxCocoa에서 제공하며, 에러나 완료를 방출하지 않고 UI 중심 작업에서 주로 사용된다.
.accept()
메서드로 값을 방출, 에러 방출 불가.let relay = BehaviorRelay(value: "Initial Value")
relay.accept("Updated Value")
relay.asObservable()
.subscribe(onNext: { value in
print(value)
})
let relay = PublishRelay<String>()
relay.accept("Event 1")
relay.asObservable()
.subscribe(onNext: { value in
print(value)
})
relay.accept("Event 2")
let button = UIButton()
button.rx.tap
.subscribe(onNext: {
print("Button tapped")
})
.disposed(by: disposeBag)
let textField = UITextField()
textField.rx.text.orEmpty
.bind(to: viewModel.inputText)
.disposed(by: disposeBag)
Rx
를 활용해서 버튼을 클릭했을 때 랜덤한 정수를 생성하고,
생성된 정수가 짝수면 버튼의 색상이 초록색,
생성된 정수가 홀수면 버튼의 색상이 빨간색으로 바뀌는 로직을 작성하고 싶어.
이때 버튼의 중복 클릭이나 과도한 연속 클릭을 방지하기 위해throttle
도 적용할거야.
import UIKit
import SnapKit
import RxSwift
import RxCocoa
struct MyError: Error {}
let ioScheduler = SerialDispatchQueueScheduler(qos: .default)
class ViewController: UIViewController {
let disposeBag = DisposeBag()
let button: UIButton = {
let button = UIButton()
button.backgroundColor = .blue
button.setTitle("버튼", for: .normal)
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
initUI()
bind()
}
func initUI() {
view.backgroundColor = .white
[button].forEach { view.addSubview($0) }
button.snp.makeConstraints {
$0.width.equalTo(120)
$0.height.equalTo(80)
$0.center.equalToSuperview()
}
}
func bind() {
button.rx.tap
.throttle(.seconds(2), scheduler: MainScheduler.instance)
.map { [weak self] in
guard let self else { throw MyError() }
return getRandomInt().isEvenNumber()
}
.subscribe(on: ioScheduler)
.observe(on: MainScheduler.instance)
.subscribe(onNext: { [weak self] isEvenNumber in
guard let self else { return }
if isEvenNumber {
button.backgroundColor = .green
} else {
button.backgroundColor = .red
}
}).disposed(by: disposeBag)
}
/// 1부터 10 중에 랜덤한 정수를 얻는 함수.
///
/// - Returns: 랜덤 정수.
func getRandomInt() -> Int {
let randomNumber = Int.random(in: 1...10)
print("랜덤 정수: \(randomNumber)")
return randomNumber
}
}
extension Int {
/// 파라미터로 들어온 정수가 짝수인지 판별하는 함수,
///
/// - Parameter number: 판별할 정수.
/// - Returns: 짝수면 true, 홀수면 false.
func isEvenNumber() -> Bool {
self % 2 == 0
}
}