RxSwift 연산자 중에서 가장 중요한 Transforming Operator(변환 연산자)에 대해서 알아보자.
let disposeBag = DisposeBag()
Observable.of("A", "B", "C") // Observable.just(["A", "B", "C"])와 같다.
.toArray()
.subscribe(onSuccess: {
print($0)
})
.disposed(by: disposeBag)
// print
// ["A", "B", "C"]
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)
// print
// 2022-01-25
protocol student {
var score : BehaviorSubject<String> { get }
}
struct grade1: student {
var score: BehaviorSubject<String>
}
let Meri = grade1(score: BehaviorSubject<String>(value: "A")) // 초기값을 가진 상태
let Jhon = grade1(score: BehaviorSubject<String>(value: "B+")) // 초기값을 가진 상태
let exam = PublishSubject<student>()
exam
.flatMap { student in
student.score
}
.subscribe(onNext: {
print($0)
})
.disposed(by: disposeBag)
exam.onNext(Meri) // 초기값 "A" 방출
Meri.score.onNext("A+")
exam.onNext(Jhon) // 초기값 "B+" 방출
Meri.score.onNext("B+")
Jhon.score.onNext("A")
// print
// A
// A+
// B+
// B+
// A
struct grade2: student {
var score: BehaviorSubject<String>
}
let Ria = grade1(score: BehaviorSubject<String>(value: "B")) // 초기값을 가진 상태
let Jey = grade1(score: BehaviorSubject<String>(value: "A+")) // 초기값을 가진 상태
let final = PublishSubject<student>()
final
.flatMapLatest { student in
student.score
}
.subscribe(onNext: {
print($0)
})
.disposed(by: disposeBag)
final.onNext(Ria) // 초기값 "B" 방출
Ria.score.onNext("B+")
final.onNext(Jey) // 초기값 "A+" 방출
Ria.score.onNext("C")
Jey.score.onNext("A")
// print
// B
// B+
// A+
// A
enum error: Error {
case stop
}
struct run: student {
var score: BehaviorSubject<String>
}
let Anne = run(score: BehaviorSubject<String>(value: "10"))
let Ven = run(score: BehaviorSubject<String>(value: "7"))
let evaluation = BehaviorSubject<student>(value: Anne)
evaluation
.flatMapLatest { student in
student.score
.materialize() // 값에 이벤트를 감싸서 함께 표시
}
.filter {
guard let error = $0.error else {
return true
}
print(error)
return false
}
.dematerialize() // 값만 표시
.subscribe(onNext: {
print($0)
})
.disposed(by: disposeBag)
Anne.score.onNext("8")
Anne.score.onError(error.stop)
Anne.score.onNext("5")
evaluation.onNext(Ven)
// print(materialize)
// next(10)
// next(8)
// stop
// next(7)
// print(dematerialize)
// 10
// 8
// stop
// 7
앞서 배운 Filtering Operator와 Transforming Operator를 사용해서 전화번호를 입력하면 010-0000-0000 형태로 보여주는 코드를 작성해 볼 것이다.
let input = PublishSubject<Int?>()
let list: [Int] = [1]
input
.flatMap { $0 == nil ? Observable.empty() : Observable.just($0) } // nil 제외
.map { $0! } // 옵셔널 처리
.skip(while: { $0 != 0 }) // 전화번호는 0으로 시작하니까, 0이 아닐때까지 건너띄기
.take(11) // 총 11자리 가져오기
.toArray() // 배열로
.asObservable() // toArray() -> Single로 되니까 다시 Observalble로 바꾸기
.map {
$0.map {"\($0)"} // Int to String
}
.map { numbers in
var numberList = numbers
numberList.insert("-", at: 3) // 010-
numberList.insert("-", at: 8) // 010-0000-
let number = numberList.reduce(" ", +)
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)
// print
// 010-1234-5678
Transforming Operator에 대해서 알아보았다.
연산자의 종류가 다양하고 처음 접해봐서 어떻게 사용해야 할지 감이 잘 안 잡힌다.
하지만, 마지막 전화번호 예시처럼 각 연산자의 기능을 잘 조합하면 효율적인 코드를 작성할 수 있겠다.