์๋ ํ์ธ์ ์ ์ธ์ ๋๋ค :)
์ ๋ฒ Rx ๊ฒ์๊ธ์ด์๋ Subject์ ์ด์ด Relay์ ๋ํด์๋ ํ ๋ฒ ์ ๋ฆฌํด๋ณด๋ ค๊ณ ํฉ๋๋ค.
์ด๋ฒ์๋ RxSwift: Reactive Programming with Swift ์ฑ ์ ์ฐธ๊ณ ํด์ ์ ๋ฆฌ๋ฅผ ํด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค!
Subject์ ๋ํด ์ ๋ชจ๋ฅด์๊ฒ ๋ค๋ฉด ์๋์ ๊ฒ์๊ธ์ ๋จผ์ ์ฝ๊ณ ์ค์๋ ๊ฒ์ ์ถ์ฒ๋๋ฆฝ๋๋ค.
Relay๋?
Relay๋ Subject์ Wrapper ํด๋์ค๋ก, RxCocoa ๋ด๋ถ์ import ๋์ด์์ต๋๋ค!
๊ทธ๋ฌ๋ฉด ์ด์ ๊ตฌ์กฐ์ ์ธ ๋ถ๋ถ์ด ๊ถ๊ธํด์ง๋๋ฐ์.. ๊ทธ๋์ ReactiveX์ Github๋ฌธ์๋ฅผ ํ์ธํด๋ณด์์ต๋๋ค..!
RxSwift ํํธ ์ค๋ช ์ ์ฐพ์๋ณด๋ฉด, <understand the structure> ์ด๋ผ๋ ํํธ์ ๋ค์๊ณผ ๊ฐ์ ์ค๋ช ์ด ๋์์์ต๋๋ค.
RxSwift์ ํต์ฌ ๋จ์๋ RxSwift ๊ทธ ์์ ์ด๋ฉฐ, UI ์์ , ํ ์คํธ ๋ฑ์ ์ํด ๋ค๋ฅธ ์ข ์์ฑ์ด ์ถ๊ฐ๋ ์ ์์ต๋๋ค.
์์ ๊ทธ๋ฆผ๊ณผ ๊ฐ์ ๋ฐฉ์์ผ๋ก ์๋ก ์์กดํ๋ ๋ค์ฏ ๊ฐ์ ๊ฐ๋ณ ๊ตฌ์ฑ ์์๋ก ๊ตฌ์ฑ๋ฉ๋๋ค.
- RxSwift: RxSwift์ ํต์ฌ์ผ๋ก, (๋๋ถ๋ถ) ReactiveX์ ์ํด ์ ์๋ Rx ํ์ค์ ์ ๊ณตํฉ๋๋ค. ๋ค๋ฅธ ์ข ์์ฑ์ ๊ฐ์ง์ง ์์ต๋๋ค.
- RxCocoa: ์ผ๋ฐ์ ์ธ iOS/macOS/watchOS & tvOS ์ฑ ๊ฐ๋ฐ์ ์ํด Shared Sequences, Traits ๋ฑ๊ณผ ๊ฐ์ ์ฝ์ฝ์ ๊ณ ์ ์ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค. ์ด๋ RxSwift์ RxRelay์ ์์กดํฉ๋๋ค.
- RxRelay: PublishRelay, BehaviorRelay, ReplayRelay ๋ผ๋ ์ธ ๊ฐ์ง Subject์ ๋ํ wrapper ํด๋์ค๋ฅผ ์ ๊ณตํฉ๋๋ค. ์ด๋ RxSwift์ ์์กดํฉ๋๋ค.
- RxTest & RxBlocking: Rx ๊ธฐ๋ฐ ์์คํ ์ ๋ํ ํ ์คํธ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค. ์ด๋ RxSwift์ ์์กดํฉ๋๋ค.
๊ทธ๋ฆผ์ผ๋ก ๋ณด๋ RxSwift์ ๊ตฌ์กฐ์ ์์กด๊ด๊ณ๊ฐ ํ๋์ ์ ํ์ ๋๋ ๊ฒ ๊ฐ์ต๋๋ค!
RxRelay๋ RxCocoa์ ๋ด์ฅ๋ Subject์ Wrapper ํด๋์ค๋ผ๊ณ ํ์ผ๋ UIEvent ์ฒ๋ฆฌ์์ Subject์ ๊ฐ์ ์ญํ ๋ก ์ฌ์ฉํ ์ ์๋ ํด๋์ค์ผ ๊ฒ ๊ฐ๋ค๋ ์ ์ถ๋ฅผ ํด๋ณผ ์ ์์ ๊ฒ ๊ฐ์๋ฐ์, Subject์์ ์ฐจ์ด์ ์ ๋ํด ๊ฐ๋ตํ๊ฒ ์ดํด๋ณด๊ณ ์ฝ๋๋ก ํ๋์ฉ ๋ณด๋ฉด์ ๋ ์์ธํ ์์๋ด ์๋ค. (์ฌ๊ธฐ์๋ถํฐ๋ raywenderlich ์ฑ ์ ๋ฒ์ญํ๋ฉด์ ์ ๋ฆฌํด๋ณด๊ฒ ์ต๋๋ค!)
observable, subject์ ๋ค๋ฅด๊ฒ relay์๋ accept(_:)๋ฉ์๋๋ฅผ ํตํด ๊ฐ์ ์ถ๊ฐํฉ๋๋ค. ์ฆ, relay์์๋ onNext(_:)๋ฅผ ์ฌ์ฉํ์ง ์์ต๋๋ค! ์๋ํ๋ฉด, relay๋ ๊ฐ์ acceptํ๋ ๊ฒ๋ง ๊ฐ๋ฅํ๊ธฐ ๋๋ฌธ์ ๋๋ค. ์ด๋ relay์ error๋ completed ์ด๋ฒคํธ๋ฅผ ์ถ๊ฐํ ์ ์๋ค๋ ๋ง๊ณผ ๋์ผํ๋ฉฐ, ์ฌ๊ธฐ์ ์ ์ ์๋ subject์์ ์ฐจ์ด์ ์ relay๋ ์ข ๋ฃ๋์ง ์์์ ๋ณด์ฅํ๋ค๋ ๊ฒ์ ๋๋ค.
PublishRelay
// 1
let relay = PublishRelay<String>()
let disposeBag = DisposeBag()
// 2
relay.accept("Knock knock, anyone home?")
// 3
relay
.subscribe(onNext: {
print($0)
})
.disposed(by: disposeBag)
// 4
relay.accept("1") // Print: 1
1๋ฒ ์ฃผ์๋ถํฐ๋ณด๋ฉด, 1์์ relay์ ์์ฑ๋ฐฉ๋ฒ์ subject์ ๋ค๋ฅธ์ ์ด ์์ต๋๋ค!
๊ทธ๋ฌ๋ 2๋ฒ์์ relay์ ๊ฐ์ ์ถ๊ฐํ๋ ๊ณผ์ ์ ๋ณด๋ฉด onNext(_:)๊ฐ ์๋ accept(_:) ๋ฉ์๋๋ฅผ ์ด์ฉํ๊ณ ์๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
2๋ฒ์์ ์๋ก์ด ๊ฐ์ ์ถ๊ฐํด์ฃผ์์ง๋ง ์์ง subscriber๊ฐ ์์ผ๋ ์๋ฌด ๊ฐ๋ ๋ฐฉ์ถ๋์ง ์๊ฒ ์ฃ ?
3๋ฒ์์ subscriber๋ฅผ ์์ฑํด์ฃผ๊ณ ์์ฑ ์ดํ 4๋ฒ์์ ์๋ก์ด ๊ฐ์ธ "1"์ ์ถ๊ฐํ๊ฒ ๋๋ฉด ์ด ๊ฐ์ด ํ๋ฆฐํธ ๋ฉ๋๋ค.
์ฌ๊ธฐ๊น์ง๋ PublishSubject์ ๋ค๋ฅธ ๊ฒ์ด ์์ต๋๋ค!
๊ทธ๋ฌ๋, relay์๋ error ํน์ completed ์ด๋ฒคํธ๋ฅผ ์ถ๊ฐํ ๋ฐฉ๋ฒ์ด ์์ต๋๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ์๋์ ๊ฐ์ ์ฝ๋๋ฅผ ์ถ๊ฐํ๋ค๋ฉด ์ปดํ์ผ๋ฌ ์ค๋ฅ๊ฐ ๋๊ฒ ๋ฉ๋๋ค.
relay.accept(MyError.anError)
relay.onCompleted()
์ ๋ฆฌํด๋ณด๋ฉด, PublishRelay๋ ์๋ก์ด ๊ฐ์ onNext(_:) ๊ฐ ์๋๋ผ accept(_:)๋ฅผ ์ด์ฉํด์ ์ถ๊ฐํ๋ค๋ ๊ฒ์ ์ ์ธํ๊ณ ๋ PublishSubject์ ๋์ผํ๊ฒ ์๋ํ๋ฉฐ ์ข ๋ฃ๋์ง ์์ต๋๋ค.
BehaviorRelay
BehaviorRelay๋ ๋น์ฐํ completed๋ error ์ด๋ฒคํธ๋ก ์ข ๋ฃ๋์ง ์๋๋ค๋ ์ ์ ๋์ผํฉ๋๋ค.
PublishRelay์ ๋ค๋ฅธ์ ์ BehaviorRelay๋ BehaviorSubject๋ฅผ ๋ํํ ํด๋์ค์ด๊ธฐ ๋๋ฌธ์ ์ด๊ธฐ๊ฐ์ ๊ฐ์ง๊ณ ์์ฑ๋๋ฉฐ ์๋ก์ด subscriber์๊ฒ ์ด๊ธฐ๊ฐ ๋๋ ์ต์ ๊ฐ์ ๋ฐฉ์ถํ๋ค๋ ๊ฒ์ ๋๋ค. ๋ํ, BehaviorRelay์ ํน๋ณํ ๊ธฐ๋ฅ์ ์ธ์ ๋ ํ์ฌ ๊ฐ์ ์์ฒญํ ์ ์๋ค๋ ๊ฒ์ธ๋ฐ, ์ด ๊ธฐ๋ฅ์ ๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ์์ ์ ์ฉํ๊ฒ ์ฌ์ฉ๋ ์ ์์ต๋๋ค.
์ฝ๋๋ก ์ดํด๋ด ์๋ค!
// 1
let relay = BehaviorRelay(value: "Initial value")
let disposeBag = DisposeBag()
// 2
relay.accept("New initial value")
// 3
relay
.subscribe {
print(label: "1)", event: $0) // Prints: 1) New initial value
}
.disposed(by: disposeBag)
์์ ์ฝ๋๋ ์ง๊ด์ ์ผ๋ก ์ดํด๊ฐ ๋ ๊ฒ ๊ฐ์๋ฐ์!
๊ฐ๋ตํ๊ฒ ์ค๋ช ํด๋ณด์๋ฉด, ์ด๊ธฐ๊ฐ์ ๊ฐ์ง๋ BehaviorRelay๋ฅผ ์์ฑํ๊ณ ์ด์ "New initial value"๋ผ๋ ๊ฐ์ accept(_:)๋ฅผ ์ด์ฉํด ์ถ๊ฐํด์ค๋๋ค. ์ดํ์ subscriber๊ฐ ์์ฑ๋์ง๋ง BehaviorRelay๋ ์๋ก์ด subscriber์๊ฒ ์ต์ ์ ๊ฐ์ ๋ฐฉ์ถํ๊ธฐ ๋๋ฌธ์ ๊ตฌ๋ ์ด์ ์ ์ถ๊ฐ๋ ๊ฐ์ด ๋ฐฉ์ถ๋์ด "1) New initial value" ๋ผ๋ ๊ฐ์ด ์ฐํ๊ฒ ๋ฉ๋๋ค.
์ด์ ์๋์ ์ฝ๋๋ฅผ ์ถ๊ฐํด๋ด ์๋ค!
// 1
relay.accept("1")
// 2
relay
.subscribe {
print(label: "2)", event: $0)
}
.disposed(by: disposeBag)
// 3
relay.accept("2")
/* Prints
1) 1
2) 1
1) 2
2) 2
*/
์์์๋ถํฐ ๋ณด๋ฉด, ์๋์ ๊ฐ์ ํ๋ฆ์ผ๋ก ์๋ก์ด ๊ฐ๊ณผ ๊ตฌ๋ ์ด ์ถ๊ฐ๋์์ต๋๋ค.
1. relay์ ์๋ก์ด ๊ฐ ์ถ๊ฐ
2. relay์ ์๋ก์ด ๊ตฌ๋ ์ถ๊ฐ
3. relay์ ๋ ๋ค๋ฅธ ์๋ก์ด ๊ฐ ์ถ๊ฐ
์ด๋ ๊ฒ ๋๋ฉด ์ด๋ฏธ ๊ตฌ๋ ํ๊ณ ์๋ 1)์ด relay์ ์ถ๊ฐ๋ "1" ์ด๋ผ๋ ๊ฐ์ ๋ฐ๊ฒ ๋์ด "1) 1" ์ด ๋จผ์ ํ๋ฆฐํธ ๋๊ณ , 2)๋ผ๋ ๊ตฌ๋ ์ด ์ถ๊ฐ๋ ๋ ์ต์ ์ ๊ฐ์ ๋ฐ๊ฒ ๋๋ ๊ทธ ๋ค์์ผ๋ก "2) 1"์ด ํ๋ฆฐํธ๋ฉ๋๋ค. ๊ทธ๋ฐ ๋ค์, 3๋ฒ ์ฃผ์์์ "2" ๋ผ๋ ๊ฐ์ด ์ถ๊ฐ๋๋ฉด 1), 2) ๊ตฌ๋ ๋ชจ๋ ๊ทธ ๊ฐ์ ๋ฐ๊ฒ ๋๋ "1) 2"์ "2) 2" ๊ฐ ์์๋๋ก ์ถ๋ ฅ๋๋ ๊ฒ์ ๋๋ค.
BehaviorRelay์๋ ์ธ์ ๋ ํ์ฌ์ ๊ฐ์ ์ ๊ทผํ ์ ์๋ค๋ ํ ๊ฐ์ง ํน๋ณํ ๊ธฐ๋ฅ์ด ์๋ค๊ณ ํ์ฃ ?
์๋์ ๊ฐ์ด relay.value ๋ก ์ ๊ทผํ ์ ์๊ณ , ์์ ์ฝ๋์์ ๊ฐ์ฅ ์ต๊ทผ์ ์ถ๊ฐ๋ "2" ๋ผ๋ ๊ฐ์ด ์ฝ์์ ์ถ๋ ฅ๋๊ฒ ๋ฉ๋๋ค.
print(relay.value) // Print: 2
ReplayRelay
ReplayRelay๋ RxSwift 6์์ ์๋กญ๊ฒ ์ถ๊ฐ๋ ์ฐ์ฐ์ ํด๋์ค์ ๋๋ค.
๋น์ฐํ ReplaySubject์ Wrapper ํด๋์ค์ด๋ฉฐ, ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ์ ํด์ง ๋ฒํผ ์ฌ์ด์ฆ๋ฅผ ๊ฐ์ง ์ฑ๋ก ์ด๊ธฐํ๋๊ณ ๋ฒํผ ์ฌ์ด์ฆ ๋งํผ์ ๊ฐ๋ค์ ์ ์งํ๋ฉด์ ์๋ก์ด subscriber์๊ฒ ๋ฐฉ์ถํ๋ค๋ ๋์ผํ ํน์ฑ์ด ์์ต๋๋ค. ๋ค๋ฅธ relay๋ค๊ณผ ๊ฐ์ด error๋ completed๋ก ์ข ๋ฃ๋์ง ์์ผ๋ฉฐ accept(_:)๋ก ์๋ก์ด ๊ฐ๋ค์ ์ถ๊ฐํ๋ค๋ ๊ฒ์ ์ ์ธํ๋ฉด ReplaySubject์ ๋์ผํ๋ ๋ฐ๋ก ์์ ์ฝ๋๋ ์ถ๊ฐํ์ง ์๊ฒ ์ต๋๋ค!
'๐ iOS > RxSwift' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[RxSwift] Traits - Driver, Signal, Control Property/ControlEvent (0) | 2023.04.29 |
---|---|
[RxSwift] Traits - Single, Completable, Maybe (0) | 2023.04.17 |
[RxSwift] Subject๋? (0) | 2023.02.03 |
[RxSwift] Observable (0) | 2022.05.02 |
[RxSwift] RxSwift์ ๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ (7) | 2022.04.07 |