Study for Udemy Lecture, MasteringRxSwift
- lecture url (udemy) : https://www.udemy.com/course/mastering-rxswift-in-ios/learn/lecture/13577704#overview
- concat(concatenate) operator는 두개의 sequence를 붙혀서 하나의 sequence로 반환한다.
- combine concatenate operator와 유사
let disposeBag = DisposeBag()
let first = Observable.of(1, 2, 3)
let second = Observable.from([4, 5, 6])
let observable = Observable.concat([first, second])
observable.subscribe(onNext: {
print($0) // 1, 2, 3, 4, 5, 6
})
- merge operator는 time based diagram 순서(시간 순)에 맞게 합쳐진 상태의 시퀀스를 반환한다. (concat operator처럼 앞 뒤 시퀀스를 단순하게 차례대로 붙히는 것이 아님)
- combine merge operator와 유사
let disposeBag = DisposeBag()
let left = PublishSubject<Int>()
let right = PublishSubject<Int>()
// left, right PublishSubject<Int>를 각각 Observable<Int>로 변환(asObservable())하여 of 연산자 인자로 넣었다.
let source = Observable.of(left.asObservable(), right.asObservable())
// left, right subject를 merge하여 left, right가 이벤트를 방출하는 시간 순으로 이벤트를 감지할 수 있다.
let observable = source.merge()
observable.subscribe(onNext: {
print($0)
}).disposed(by: disposeBag)
// left, right subject가 이벤트를 방출하는 time 순으로 이벤트가 방출된다.
left.onNext(10)
left.onNext(20)
right.onNext(30)
right.onNext(40)
left.onNext(50)
- combineLatest operator는 다수 Observable 각각의 최신 이벤트를 방출한다.
- combine의 combineLatest와 동일
let disposeBag = DisposeBag()
let left = PublishSubject<Int>()
let right = PublishSubject<Int>()
let observable = Observable.combineLatest(left, right, resultSelector: { lastLeft, lastRight in
"left : \(lastLeft), right : \(lastRight)"
})
let disposable = observable.subscribe(onNext: { value in
print(value)
})
// combineLatest는 Observable의 최신상태 이벤트를 방출할때 사용한다. 텍스트필드 유효성 검사 등에 사용할 수 있다.
left.onNext(1)
right.onNext(3) // left : 1, right : 3
left.onNext(2) // left : 2, right : 3
right.onNext(100) // left : 2, right : 100
right.onNext(200) // left : 2, right : 200
left.onNext(300) // left : 300, right : 200
- withLatestFrom을 통해 특정 Observable 인자에 대한 최신 이벤트 값을 받을 수 있다.
- ex) button이 withLatestFrom 인자로 특정 텍스트필드 Observable을 넣으면, button이 클릭될 때마다 텍스트필드의 최신 값을 감지할 수 있다.
- combine의 switchToLatest와 살짝 유사한 역할이 있는 것 같다. 다만, combine에서는 publisher를 output으로 가진 subject에서 사용 가능, RxSwift에서는 단순 subject에서도 접근해서 사용 가능
let disposeBag = DisposeBag()
let button = PublishSubject<Void>()
let textField = PublishSubject<String>()
let observable = button.withLatestFrom(textField)
let disposable = observable.subscribe(onNext: {
print($0)
})
textField.onNext("Sw")
textField.onNext("Swif")
textField.onNext("Swift") // 버튼이 클릭되기 전까지는 구독한 observable의 이벤트가 방출되지 않는다.
// button subject가 Void 이벤트를 방출할때마다(클릭할때마다) 구독한 observable을 통해 클릭 직후의 텍스트필드 최신 이벤트를 받을 수 있다.
button.onNext(()) // -> Swift
button.onNext(()) // -> Swift
- reduce operator는 초기값을 지정하고 Sequence에 대한 연산을 통해 하나의 결과 값으로 반환한다.
- combine의 reduce와 유사
let disposeBag = DisposeBag()
let source = Observable.of(1, 2, 3)
source.reduce(0, accumulator: +) // 1 + 2 + 3 == 6
.subscribe(onNext: {
print($0) // 6
}).disposed(by: disposeBag)
source.reduce(0, accumulator: { summary, value in
return summary + value // accumulator 클로져를 통해 커스텀하게 연산이 가능하다. 위와 동일하게 모든 value의 합을 반환하는 연산이다.
}).subscribe(onNext: {
print($0) // 6
}).disposed(by: disposeBag)
- scan operator는 reduce operator와 친척같은(유사한) 형태의 연산자이다.
- combine의 scan과 유사
- reduce는 Sequence 누적 연산의 마지막 결과 값만 반환하지만, scan은 그 연산 과정 결과도 함께 반환한다.
let disposeBag = DisposeBag()
let source = Observable.of(1, 2, 3, 4, 5)
source.scan(0, accumulator: +)
.subscribe(onNext: {
// 1, 3, 6, 10, 15 -> 마지막 결과 값, 15만 출력되는 reduce와 달리 scan operator는 중간 연산 과정도 함께 출력된다.
print($0)
}).disposed(by: disposeBag)
- RxCocoa는 많은 UIControl, 그 외 SDK 클래스 들에 대한 이벤트를 observable하게 관찰하고 binding하기 위한 커스텀 wrapper function을 제공한다.
- RxCocoa를 통해 기존 UI에 대한 Reactive한 접근이 가능하다. iOS, Apple Watch, Apple TV, macOS 등 다양한 플랫폼을 지원한다.
- RxCocoa example project에 사용되는 weather open api link
- catchAndReturn : 에러 발생 시 지정된 특정 값을 전달
- retry : 에러 발생 시 재시도
- MVC 패턴 : MVC, Model, ViewController로 구성되는 디자인패턴, 가장 구현난이도가 쉬워 진입장벽이 낮지만, ViewController의 역할이 커서 Messive ViewController, bad testability 의 문제점이 있다.
- MVVM패턴, View, ViewModel, Model로 구성되는 디자인패턴으로 MVC의 문제점을 해소하고, testabiliity를 개선할 수 있다.
- ViewModel에 비즈니스로직이 들어가며, ViewModel은 View와 Binding된다.
- Binding에는 RxSwift/RxCocoa, Combine을 사용할 수 있다.
- SwiftUI의 경우 State, ObservableObject 등의 Propertywrapper를 사용하여 binding할 수도 있음
- Model, View는 서로 직접적으로 소통하지 않는다. ViewModel에서 복잡한 구조는 Model로 분리될 수 있다.