๐ 1 . Subject
Subject๋ ๋ค๋ฆฌ, ํ๋ก์ ์ญํ ๋ก ๋ฐ์ดํฐ์ ์ค๊ณ ์ญํ ์ ํ๋ ๊ฐ์ฒด์ด๋ค.
๋ฐ์ดํฐ๋ฅผ ๋ฐ์์ ๊ตฌ๋ ์๋ค์๊ฒ ์ฌ์ ์กํ๊ฑฐ๋ ์๋ก์ด ๋ฐ์ดํฐ๋ฅผ ์ง์ ๋ฐํํ๋ค.
๋ฐ๋ผ์, Subject๋ ์ต์ ๋ฒ์ด๋ฉด์ ๋์์ ์ต์ ๋ฒ๋ธ์ด๋ค.
Subject๋ ํ๋ ์ด์์ ๋ค๋ฅธ ์ต์ ๋ฒ๋ธ์ ๊ตฌ๋ ํ ์ ์๊ณ (์ต์ ๋ฒ ์ญํ ), ๋์์ ์ต์ ๋ฒ๋ธ์ด๋ฏ๋ก ๊ตฌ๋ ์์๊ฒ ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํ ์ ์๋ค.
* ์ต์ ๋ฒ๋ธ์ ๋ค๋ฅธ ์ต์ ๋ฒ๋ธ์ ๊ตฌ๋ ํ์ง ๋ชปํ๋ค. ์ต์ ๋ฒ๋ ๋ค๋ฅธ ์ต์ ๋ฒ์๊ฒ ์ด๋ฒคํธ๋ฅผ ์ ๋ฌํ์ง ๋ชปํ๋ค.
๐ 2. Subject์ ์ข ๋ฅ
Subject๋ .next ์ด๋ฒคํธ๋ฅผ ๋ฐ๊ณ , ์ด๋ฒคํธ๋ฅผ ์์ ํ ๋๋ง๋ค ๊ตฌ๋ ์์๊ฒ ๋ฐฉ์ถํ๋ค.
๊ธฐ๋ณธ์ ์ผ๋ก ์ต์ ๋ฒ๋ธ์ cold ์ต์ ๋ฒ๋ธ๋ก ๋์ํ๊ธฐ ๋๋ฌธ์ ๊ตฌ๋ ์๊ฐ ์๋ก์ด ๊ฐ์ ๋ฐ์ ๋๋ง๋ค ์ฒ์๋ถํฐ ์ด๋ฒคํธ๋ฅผ ๋ค์ ์์ฑํ๋ค.
ํ์ง๋ง ์ฌ๋ฌ ๊ตฌ๋ ์์๊ฒ ๋์ผํ ๋ฐ์ดํฐ ์คํธ๋ฆผ์ ๊ณต์ ํด์ผํ๋ ์ํฉ์์๋ Subject๋ฅผ ์ด์ฉํด
ํ๋์ ์คํธ๋ฆผ์ ์ฌ๋ฌ ๊ตฌ๋ ์์๊ฒ ๋์์ ์ ๊ณตํ ์ ์๋ค.
Subject๋ฅผ ์ฌ์ฉํด ํ๋์ ์ด๋ฒคํธ ์คํธ๋ฆผ์ ๋๊ฐ์ ๊ตฌ๋ ์๊ฐ ๊ณต์
import RxSwift
let disposeBag = DisposeBag()
// PublishSubject ์์ฑ
let subject = PublishSubject<String>()
// ์ฒซ ๋ฒ์งธ ๊ตฌ๋
์
subject.subscribe(onNext: { value in
print("์ฒซ ๋ฒ์งธ ๊ตฌ๋
์๊ฐ ๋ฐ์ ๊ฐ: \(value)")
}).disposed(by: disposeBag)
// ๋ ๋ฒ์งธ ๊ตฌ๋
์
subject.subscribe(onNext: { value in
print("๋ ๋ฒ์งธ ๊ตฌ๋
์๊ฐ ๋ฐ์ ๊ฐ: \(value)")
}).disposed(by: disposeBag)
// ์ธ๋ถ์์ ์ด๋ฒคํธ ๋ฐฉ์ถ
subject.onNext("๊ณต์ ๋ ์ด๋ฒคํธ 1")
subject.onNext("๊ณต์ ๋ ์ด๋ฒคํธ 2")
*์๋ ์ฝ๋ ์์๋ฅผ ์ดํดํ ๋ ์ฐธ๊ณ *
๋ฒํผ ํด๋ฆญ ์ด๋ฒคํธ๋ฅผ ์ฒ๋ฆฌํ ๋, ๋ฒํผ ํด๋ฆญ ์ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ๋ ์ฝ๋๊ฐ ๊ตฌ๋ ์ ์ญํ ์ ํ๊ฒ ๋๋ค.
๋ฒํผ์ ํด๋ฆญํ๋ฉด onNext๋ก ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ๊ณ ๊ทธ๊ฑธ ๊ตฌ๋ ์(onNext ํด๋ก์ ๋ถ๋ถ)๊ฐ ๋ฐ์์ ์ฒ๋ฆฌํ๋ ๊ตฌ์กฐ์ด๋ค.
1. PublishSubject
๊ตฌ๋ ์ด ์์๋ ์ดํ ๋ฐ์ํ ์ด๋ฒคํธ๋ง ๊ตฌ๋ ์์๊ฒ ๋ฐฉ์ถํ๋ค.
๊ตฌ๋ ์ ๋ฉ์ถ๊ฑฐ๋ .completed, .error ์ด๋ฒคํธ๋ฅผ ํตํด Subject๊ฐ ์ข ๋ฃ๋ ๋๊น์ง ์ง์๋๋ค.
์ ํฉํ ์ํฉ
- ์ด์ ์ ์ด๋ฒคํธ๋ ์ค์ํ์ง ์์ ๊ฒฝ์ฐ
- ๊ตฌ๋ ์ ์์ํ ์ดํ๋ถํฐ ๋ฐ์ํ๋ ์ด๋ฒคํธ๋ง ๋ฐ๊ณ ์ถ์ ๋
- ์์) ๋ฒํผ ํด๋ฆญ ์ด๋ฒคํธ์ฒ๋ผ ๊ณผ๊ฑฐ์ ๋ฒํผ์ ๋๋ฅธ ๊ธฐ๋ก์ ์ค์ํ์ง ์๊ณ , ๊ตฌ๋ ์ด ์์๋ ์ดํ์ ๋ฐ์ํ ํด๋ฆญ ์ด๋ฒคํธ๋ง ๋ค๋ฃจ๊ณ ์ถ์ ๋
let publishSubject = PublishSubject<String>()
// 1.Subject๊ฐ ์ด๋ฒคํธ๋ฅผ ๋ฐ์์ํค๋ฉด(onNext๋ฅผ ํธ์ถํ๋ฉด)
publishSubject.onNext("์ด๋ฒคํธ 1") // ์ต์ ๋ฒ๋ธ์ด ๊ตฌ๋
์์๊ฒ ์ด๋ฒคํธ๋ฅผ ๋ฐฉ์ถํ์ง๋ง ์์ง ๊ตฌ๋
์๊ฐ ์๊ธฐ ๋๋ฌธ์ ์ ๋ฌ๋์ง ์์
// 2.๊ตฌ๋
์๊ฐ ๊ทธ ์ด๋ฒคํธ๋ฅผ ๋ฐ์์ ์ฒ๋ฆฌ(onNext ํด๋ก์ ๊ฐ ํธ์ถ๋จ)
// 3.value์ ์ด๋ฒคํธ๊ฐ ์ ๋ฌ๋๊ณ , print() ์คํ
publishSubject.subscribe(onNext: { value in // onNext ํด๋ก์ ๋ถ๋ถ์ด ๊ตฌ๋
์(subscriber)
print("๋ฐ์ ์ด๋ฒคํธ: \(value)")
})
publishSubject.onNext("์ด๋ฒคํธ 2") // ๊ตฌ๋
ํ ์ด๋ฒคํธ๋ง ์ ๋ฌ๋จ
// ๊ตฌ๋
์ ์ธ ์ด๋ฒคํธ1์ ๋ฌด์๋๊ณ ๊ตฌ๋
์ดํ์ธ ์ด๋ฒคํธ2๋ง ์ ๋ฌ๋จ.
์ฌ์ฉ์๊ฐ ๋ฒํผ์ ๋๋ ์ ๋ ์ด๋ฒคํธ๋ฅผ ๋ฐ์์ํค๋ ค๋ฉด, ๋ฒํผ์ ์ก์ ๊ณผ onNext ๋ฉ์๋๋ฅผ ์ฐ๊ฒฐํด์ผํ๋ค.
๋ฒํผ์ ๋๋ฅด๋ฉด ๊ทธ ์๊ฐ์ onNext๊ฐ ํธ์ถ๋๊ณ ๊ทธ๋ก์ธํด ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ๋ค.
๋ฒํผ์ ๋๋ฅด๋ ํ๋ฆ:
๋ฒํผ ํด๋ฆญ ์ → button.rx.tap์ด ๊ฐ์ง → subject.onNext("๋ฒํผ์ด ๋๋ ธ์ต๋๋ค!")๊ฐ ํธ์ถ๋จ → subject์ ๊ตฌ๋ ์๊ฐ ๊ทธ ์ด๋ฒคํธ๋ฅผ ๋ฐ์์ print๋ก ์ถ๋ ฅํจ.
import UIKit
import RxSwift
import RxCocoa
class ViewController: UIViewController {
let disposeBag = DisposeBag()
let subject = PublishSubject<String>() // Subject ์์ฑ
override func viewDidLoad() {
super.viewDidLoad()
// ๋ฒํผ ์์ฑ ๋ฐ ์ค์
let button = UIButton(type: .system)
button.setTitle("์ด๋ฒคํธ ๋ฐ์", for: .normal)
button.frame = CGRect(x: 100, y: 100, width: 200, height: 50)
self.view.addSubview(button)
// ๋ฒํผ ํด๋ฆญ ์ Subject์ ์ด๋ฒคํธ ๋ฐ์ (onNext ํธ์ถ)
button.rx.tap // ๋ฒํผ์ Rx๋ก ๋ณํํ์ฌ ํด๋ฆญ ์ด๋ฒคํธ๋ฅผ ๊ฐ์ง
.subscribe(onNext: { [weak self] in
self?.subject.onNext("๋ฒํผ์ด ๋๋ ธ์ต๋๋ค!")
})
.disposed(by: disposeBag)
// Subject ๊ตฌ๋
์ค์ (์ด๋ฒคํธ๊ฐ ๋ฐ์ํ๋ฉด ์ฒ๋ฆฌ)
subject.subscribe(onNext: { value in
print("๋ฐ์ ์ด๋ฒคํธ: \(value)")
}).disposed(by: disposeBag)
}
}
2. BehaviorSubject
ํ๋์ ์ด๊ธฐ๊ฐ์ ๊ฐ์ง ์ํ๋ก ์์ํ์ฌ, ์๋ก์ด ๊ตฌ๋ ์์๊ฒ ์ด๊ธฐ๊ฐ ๋๋ ์ต์ ๊ฐ์ ๋ฐฉ์ถํ๋ค.
์ ํฉํ ์ํฉ
- ๊ตฌ๋ ์๊ฐ ์ด์ ์ ๋ฐ์ํ ๊ฐ์ฅ ์ต๊ทผ์ ๋ฐ์ดํฐ๋ ํ์๋ก ํ ๊ฒฝ์ฐ
- ์์) ์ฌ์ฉ์์ ํ์ฌ ์ํ๋ ์ค์ ๊ฐ์ฒ๋ผ ๊ณผ๊ฑฐ์ ๋ง์ง๋ง ๊ฐ์ด ์ค์ํ ๋.
๊ตฌ๋ ์๊ฐ ํ์ํ ๋๋ง๋ค ๊ฐ์ฅ ์ต์ ์ ๊ฐ์๊ฐ์ ธ์์ผํ ๋
let behaviorSubject = BehaviorSubject(value: "์ด๊ธฐ๊ฐ")
// ์ด๊ธฐ๊ฐ์ ์ค์ ํ์ง๋ง ๊ณง๋ฐ๋ก ์ด๋ฒคํธ1์ด ๋ฐ์ํ๋ฉด์ ์ด๊ธฐ๊ฐ ๋ฎ์ด์ฐ์ฌ์ง.
behaviorSubject.onNext("์ด๋ฒคํธ 1") // ์ด๋ฒคํธ1 ๋ฐฉ์ถ. ๊ตฌ๋
์๊ฐ ์์ผ๋ฏ๋ก ์ผ๋จ ๊ธฐ์ต๋ง ํ๊ณ ์์
behaviorSubject.subscribe(onNext: { value in
print("๋ฐ์ ์ด๋ฒคํธ: \(value)") // ๊ตฌ๋
์๊ฐ ์๊ธฐ์๋ง์ ๋ง์ง๋ง์ผ๋ก ๊ธฐ์ตํ ๊ฐ์ธ ์ด๋ฒคํธ1์ ๋ฐ๋ก ๊ตฌ๋
์์๊ฒ ์ ๋ฌ.
})
behaviorSubject.onNext("์ด๋ฒคํธ 2") // ์ด๋ฒคํธ2๊ฐ ๊ตฌ๋
์์๊ฒ ์ ๋ฌ๋จ
//์ถ๋ ฅ ๊ฒฐ๊ณผ
๋ฐ์ ์ด๋ฒคํธ: ์ด๋ฒคํธ 1
๋ฐ์ ์ด๋ฒคํธ: ์ด๋ฒคํธ 2
===============================
let behaviorSubject = BehaviorSubject(value: "์ด๊ธฐ๊ฐ") // ์ด๊ธฐ๊ฐ ์ค์
// ๊ตฌ๋
์๊ฐ ์๊ธฐ๋ฉด ์ด๊ธฐ๊ฐ์ ์ ๋ฌ
behaviorSubject.subscribe(onNext: { value in
print("๋ฐ์ ์ด๋ฒคํธ: \(value)")
})
// ์ด์ onNext๋ฅผ ํธ์ถํ์ฌ ์ถ๊ฐ ์ด๋ฒคํธ ๋ฐฉ์ถ
behaviorSubject.onNext("์ด๋ฒคํธ 1")
behaviorSubject.onNext("์ด๋ฒคํธ 2")
//์ถ๋ ฅ ๊ฒฐ๊ณผ
๋ฐ์ ์ด๋ฒคํธ: ์ด๊ธฐ๊ฐ
๋ฐ์ ์ด๋ฒคํธ: ์ด๋ฒคํธ 1
๋ฐ์ ์ด๋ฒคํธ: ์ด๋ฒคํธ 2
===============================
let disposeBag = DisposeBag()
// ์ด๊ธฐ ๊ฐ์ ๊ฐ์ง BehaviorSubject ์์ฑ
let subject = BehaviorSubject(value: "์ด๊ธฐ ๊ฐ")
// ์ฒซ ๋ฒ์งธ ๊ตฌ๋
์๊ฐ ๊ตฌ๋
subject.subscribe(onNext: { value in
print("์ฒซ ๋ฒ์งธ ๊ตฌ๋
์๊ฐ ๋ฐ์ ๊ฐ: \(value)")
}).disposed(by: disposeBag)
// ์๋ก์ด ๊ฐ ๋ฐฉ์ถ
subject.onNext("์๋ก์ด ๊ฐ 1")
// ๋ ๋ฒ์งธ ๊ตฌ๋
์๊ฐ ๊ตฌ๋
(์ด์ ๊ฐ์ธ '์๋ก์ด ๊ฐ 1'์ ๋ฐ๊ฒ ๋จ)
subject.subscribe(onNext: { value in
print("๋ ๋ฒ์งธ ๊ตฌ๋
์๊ฐ ๋ฐ์ ๊ฐ: \(value)")
}).disposed(by: disposeBag)
3. ReplaySubject
์ต์ ๋ฒ๊ฐ ๊ตฌ๋ ์ ์์ํ ์์ ๊ณผ ๊ด๊ณ ์์ด ์ต์ ๋ฒ๋ธ์ด ๋ฐฐ์ถํ ๋ชจ๋ ํญ๋ชฉ๋ค์ ๋ชจ๋ ๊ตฌ๋ ์์๊ฒ ๋ฐฉ์ถํ๋ค.
๊ตฌ๋ ์๊ฐ ์๊ธด ์ดํ์๋ ์ง์ ๋ ๋ฒํผ์ ํฌ๊ธฐ๋งํผ ์ด์ ์ ๋ฐฉ์ถ๋ ์ด๋ฒคํธ๋ฅผ ๋ค์ ๋ฐฉ์ถํ๋ค.
์ด๋ก ์ธํด ์๋ก์ด ๊ตฌ๋ ์๊ฐ ์ง์ ๋ ๋ฒ์ ๋ด์์์ ์ด์ ๊ฐ์ ๋ฐ์ ์ ์๋ค. -> ๋ฐ์ดํฐ๋ฅผ ์บ์ํด์ผ ํ ๋ ์ ์ฉํจ.
๋ฒํผ์ ํฌ๊ธฐ๊ฐ ์ด๊ณผ๋๋ฉด ๊ฐ์ฅ ์ค๋๋ ๊ฐ๋ถํฐ ์ญ์ ๋๋ค.
์ ํฉํ ์ํฉ
- ๊ฒ์์ฐฝ์์ ์ต๊ทผ 5๊ฐ์ ๊ฒ์์ด๋ฅผ ๋ณด์ฌ์ฃผ๊ณ ์ถ์ ๋
let disposeBag = DisposeBag()
// 2๊ฐ์ ๋ฒํผ๋ฅผ ๊ฐ์ง ReplaySubject ์์ฑ
let subject = ReplaySubject<String>.create(bufferSize: 2)
// ๋ ๊ฐ์ ๊ฐ์ ๋ฐฉ์ถ
subject.onNext("์ด์ ๊ฐ 1")
subject.onNext("์ด์ ๊ฐ 2")
subject.onNext("์ด์ ๊ฐ 3")
// ์๋ก์ด ๊ตฌ๋
์๊ฐ ๊ตฌ๋
(๊ฐ์ฅ ์ต๊ทผ์ ๋ ๊ฐ ๊ฐ๋ง ๋ฐ์)
subject.subscribe(onNext: { value in
print("๊ตฌ๋
์๊ฐ ๋ฐ์ ๊ฐ: \(value)")
}).disposed(by: disposeBag)
// ์ถ๋ ฅ ๊ฒฐ๊ณผ
๊ตฌ๋
์๊ฐ ๋ฐ์ ๊ฐ: ์ด์ ๊ฐ 2
๊ตฌ๋
์๊ฐ ๋ฐ์ ๊ฐ: ์ด์ ๊ฐ 3
/* ReplaySubject๋ ์ต๋ 2๊ฐ์ ์ด๋ฒคํธ๋ฅผ ์บ์ฑํ๊ณ ์์.
์๋ก์ด ๊ตฌ๋
์๋ ๋ง์ง๋ง ๋ ๊ฐ์ ์ด๋ฒคํธ๋ง ๋ฐ์.
๋ฐ์ดํฐ๋ฅผ ์ผ๋ถ๋ถ ์บ์ํ๊ณ ์๋ก์ด ๊ตฌ๋
์์๊ฒ ์ ๊ณตํด์ผ ํ ๋ ์ ์ฉ */
4. AsyncSubject
์์ ์ด ์๋ฃ๋ ํ์๋ง ๋ง์ง๋ง ๊ฐ์ ์ ๋ฌํ๋ค.
onCompleted๊ฐ ํธ์ถ๋ ํ์๋ง ๋ง์ง๋ง ์ด๋ฒคํธ๋ฅผ ์ ๋ฌํ๋ค.
์ ํฉํ ์ํฉ
- ๊ฒฐ๊ณผ๊ฐ ์๋ฃ๋ ํ์๋ง ํน์ ๊ฐ์ ์ ๋ฌํด์ผํ ๋
- ์์) ๋ณต์กํ ๊ณ์ฐ์ด ๋๋ ํ ๊ทธ ๊ฒฐ๊ณผ๋ง ์ ๋ฌํ๋ ์ํฉ, ๋คํธ์ํฌ ์์ฒญ์ด ๋๋ฌ์ ๋ ์ต์ข ์๋ต ๋ฐ์ดํฐ๋ง ์ ๋ฌํ๋ ์ํฉ
let disposeBag = DisposeBag()
let subject = AsyncSubject<String>()
subject.subscribe(onNext: { value in
print("๊ตฌ๋
์๊ฐ ๋ฐ์ ๊ฐ: \(value)")
}).disposed(by: disposeBag)
// ์ฌ๋ฌ ๊ฐ์ ๊ฐ์ ๋ฐฉ์ถํ์ง๋ง ์๋ฃ ์ ๊น์ง ๊ตฌ๋
์๋ ๊ฐ์ ๋ฐ์ง ์์
subject.onNext("์ด๋ฒคํธ 1")
subject.onNext("์ด๋ฒคํธ 2")
// ์๋ฃ ์ด๋ฒคํธ๊ฐ ๋ฐ์ํด์ผ ๊ตฌ๋
์๊ฐ ๋ง์ง๋ง ๊ฐ์ ๋ฐ์
subject.onCompleted()
// ์ถ๋ ฅ๊ฒฐ๊ณผ
๊ตฌ๋
์๊ฐ ๋ฐ์ ๊ฐ: ์ด๋ฒคํธ 2
๐ Reference
https://github.com/fimuxd/RxSwift/blob/master/Lectures/03_Subjects/Ch3.%20Subjects.md
'๐ iOS > RxSwift' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[ RxSwift ] Relay๋ฅผ ์์๋ณด์ (2) | 2024.10.15 |
---|---|
[ Rxswift ] Observable์ ์์๋ณด์ (3) | 2024.10.04 |