toArray
Observable 의 독립적 요소들을 Array 로 만들 수 있는 방법이다.
print("--------toArray--------")
Observable.of("A", "B", "C")
.toArray()
.subscribe(onSuccess: {
print($0)
})
.disposed(by: disposeBag)
--------toArray--------
["A", "B", "C"]
map
Observable 에서 동작한다는 점만 제외하면 Swift 에서의 map 과 동일하다.
print("--------map--------")
Observable.of(Date())
.map { date -> String in
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
dateFormatter.locale = Locale(identifier: "ko_KR")
return dateFormatter.string(from: date)
}
.subscribe(onNext: {
print($0)
})
.disposed(by: disposeBag)
--------map--------
2022-11-01
flatMap
Observable 속성을 갖는 Observable 은 어떻게 사용할 수 있을까?
flatMap 을 통해 중첩된 Observable 속의 element 를 가져오거나 핸들링할 수 있다.
print("--------flatMap--------")
protocol 선수 {
var 점수: BehaviorSubject<Int> { get }
}
struct 양궁선수: 선수 {
var 점수: BehaviorSubject<Int>
}
let 🇰🇷국가대표 = 양궁선수(점수: BehaviorSubject(value: 10))
let 🇺🇸국가대표 = 양궁선수(점수: BehaviorSubject(value: 8))
let 올림픽경기 = PublishSubject<선수>()
올림픽경기
.flatMap { 선수 in
선수.점수
}
.subscribe(
onNext: {
print($0)
}
)
.disposed(by: disposeBag)
올림픽경기.onNext(🇰🇷국가대표)
🇰🇷국가대표.점수.onNext(10)
올림픽경기.onNext(🇺🇸국가대표)
🇰🇷국가대표.점수.onNext(10)
🇺🇸국가대표.점수.onNext(9)
--------flatMap--------
10
10
8
10
9
flatMapLatest
flatMapLatest는 가장 최신의 값 만을 확인하고 싶을 때 사용한다. 예시를 든다면, 전국체전이라는 Sequence 가 가지고 있는 선수.점수 라는 sequence 의 가장 최신의 값 만을 반영하겠다라는 것이다.
flapMapLatest 는 가장 최근의 Observable 로 전환하여 새로운 Sequence 가 발생한 이후(제주), 이전의 Observable (서울)은 구독 해제한다.
Networking 조작에서 가장 흔하게 사용한다. 사전으로 단어를 찾는 것을 가정해보자. 사용자가 s, w, i, f, t 를 순차적으로 입력 시 새 검색을 실행한다. s 를 쳤을 시 s 를 검색하고, 그 이후 w 를 입력 시 s 에 대한 검색값이 남아있지 않다. 새로운 String 을 입력할 때 마다 가장 최신의 String 에 맞는 검색값을 보여준다. 이러한 경우 flapMapLatest 를 사용할 수 있다.
print("--------flatMapLatest--------")
struct 높이뛰기선수: 선수 {
var 점수: BehaviorSubject<Int>
}
let 서울 = 높이뛰기선수(점수: BehaviorSubject(value: 7))
let 제주 = 높이뛰기선수(점수: BehaviorSubject(value: 6))
let 전국체전 = PublishSubject<선수>()
전국체전
.flatMapLatest {
$0.점수
}
.subscribe(onNext: {
print($0)
})
.disposed(by: disposeBag)
전국체전.onNext(서울) // 7
서울.점수.onNext(9) // 9
전국체전.onNext(제주) // 6
서울.점수.onNext(10) // 9 가 최신의 값이기 때문에 무시
제주.점수.onNext(8) // 8
--------flatMapLatest--------
7
9
6
8
materialize and dematerialize
Observable 을 Observable 의 이벤트로 변환해야할 때가 있을 수 있다. 보통 Observable 속성을 가진 Observable 항목을 제어할 수 없고, 외부적으로 Observable 이 종료되는 것을 방지하기 위해 Error 이벤트를 처리하고 싶을 수도 있다
print("--------materialize and dematerialize--------")
enum 반칙: Error {
case 부정출발
}
struct 달리기선수: 선수 {
var 점수: BehaviorSubject<Int>
}
let 김토끼 = 달리기선수(점수: BehaviorSubject(value: 0))
let 박치타 = 달리기선수(점수: BehaviorSubject(value: 1))
let 달리기100M = BehaviorSubject<선수>(value: 김토끼)
달리기100M
.flatMapLatest {
$0.점수
}
.subscribe(onNext: {
print($0)
})
.disposed(by: disposeBag)
김토끼.점수.onNext(1)
김토끼.점수.onError(반칙.부정출발)
김토끼.점수.onNext(2)
달리기100M.onNext(박치타)
--------materialize and dematerialize--------
0
1
Unhandled error happened: 부정출발
materialize 를 추가하면, 이벤트를 감싸서 요소를 표현한다.
달리기100M
.flatMapLatest {
$0.점수
.materialize() // 1) materialize 추가
}
.filter {
guard let error = $0.error else {
return true
}
print(error)
return false
}
.dematerialize()
.subscribe(onNext: {
print($0)
})
.disposed(by: disposeBag)
김토끼.점수.onNext(1)
김토끼.점수.onError(반칙.부정출발)
김토끼.점수.onNext(2)
달리기100M.onNext(박치타)
--------materialize and dematerialize--------
next(0)
next(1)
error(부정출발)
next(1)
dematerialize 란?
print("--------materialize and dematerialize--------")
// Observable 을 Observable 의 이벤트로 변환해야할 때가 있을 수 있다.
// 보통 Observable 속성을 가진 Observable 항목을 제어할 수 없고, 외부적으로 Observable 이 종료되는 것을 방지하기 위해 Error 이벤트를 처리하고 싶을 수 있다
enum 반칙: Error {
case 부정출발
}
struct 달리기선수: 선수 {
var 점수: BehaviorSubject<Int>
}
let 김토끼 = 달리기선수(점수: BehaviorSubject(value: 0))
let 박치타 = 달리기선수(점수: BehaviorSubject(value: 1))
let 달리기100M = BehaviorSubject<선수>(value: 김토끼)
달리기100M
.flatMapLatest {
$0.점수
.materialize() // 1) materialize 추가
}
.filter {
guard let error = $0.error else {
// 통과 O
return true
}
print(error)
// 통과 X
return false
}
.dematerialize()
.subscribe(onNext: {
print($0)
})
.disposed(by: disposeBag)
김토끼.점수.onNext(1)
김토끼.점수.onError(반칙.부정출발)
김토끼.점수.onNext(2)
달리기100M.onNext(박치타)
--------materialize and dematerialize--------
0
1
부정출발
1
종합 예시
print("--------전화번호 11자리--------")
let input = PublishSubject<Int?>()
let list: [Int] = [1]
input
.flatMap {
$0 == nil ? Observable.empty() : Observable.just($0)
}
.map { $0! }
.skip(while: { $0 != 0 }) // 010-.. 첫번째 0
.take(11) // 총 11자리
.toArray() // Array 로 묶기
.asObservable() // 다시 Observable
.map {
$0.map { "\($0)" } // Int -> String 타입으로 변경
}
.map { numbers in
var numberList = numbers
numberList.insert("-", at: 3)
numberList.insert("-", at: 8)
let number = numberList.reduce(" ", +) // 각각의 String 을 더한다
return number
}
.subscribe(onNext: {
print($0)
})
.disposed(by: disposeBag)
input.onNext(10)
input.onNext(0)
input.onNext(nil)
input.onNext(1)
input.onNext(0)
input.onNext(1)
input.onNext(2)
input.onNext(nil)
input.onNext(3)
input.onNext(4)
input.onNext(5)
input.onNext(6)
input.onNext(7)
input.onNext(8)
--------전화번호 11자리--------
010-1234-5678
' iOS > RxSwift' 카테고리의 다른 글
RxSwift - 여러 개의 Observable 을 합치는 방법(combineLatest) (0) | 2022.11.06 |
---|---|
RxSwift - MVVM 디자인 패턴 (0) | 2022.11.05 |
RxSwift - Filter (1) | 2022.11.01 |
RxSwift - Subject (0) | 2022.11.01 |
RxSwift - Traits (Single, Maybe, Completable) (0) | 2022.10.31 |