티스토리 뷰
Observable vs Observer
옵저버블 - 이벤트를 emit
옵저버 - 이벤트 처리
옵저버블과 옵저버를 통해 데이터 스트림을 통제할 수 있고, Operator를 통해 조작할 수 있음
근데 옵저버블은 이벤트에 대한 처리를 할 수 없고, 옵저버는 이벤트에 대한 처리만 가능함.
-> 그래서 Subject나옴
Subject
위에서 말했듯이 emit과 Subscribe 둘 다 가능.
네 가지 종류가 있음
Publish, Behavior, Replay, Async
근데 UI의 경우는 에러가 날 일이 거의 없음.
그래서 핸들링도 딱히 필요없고, 이벤트에 대한 요소도 대부분 infinite
RxSwift로도 충분했지만, UI를 더 잘 관리할 수 있는게 RxCocoa
onNext를 전달할 수 있다는 것은, error와 complete도 전달할 수 있다는 의미
-> 근데 UI에서는 거의 실패할 가능성이 없음
-> 그냥 안쓰고 onNext만 사용하면 되긴하지만 next만 전달하는 요소인 Replay가 있음
Replay
UI적인 부분을 만지는데 더 최적화되어있음
Publish와 Behavior가 있고 Subject와 거의 유사함
차이는 Replay는 Completed와 Error이벤트를 받지 못함
만약 UI가 Completed와 Error를 받으면 disposed상태가 되는데, 이렇게 되면 더 이상 next이벤트를 전달받을 수 없음
-> 반응형의 장점이 사라짐
즉, Replay를 사용하게되면 Completed와 Error를 받을 수 없다는 얘기이고, 이는 disposed가 되기 전까지 Subscribe가 해제되지 않는다는 것을 의미함
-> 그래서 직접 처리를 해줘야함
Subject에서의 next가 Replay에서는 accept.
Subject는 Observable과 자주 사용되고, Relay는 driver와 자주 사용이됨(짝꿍)
Subscribe -> bind -> drive
버튼을 탭했을때 레이블에 텍스트를 띄우는 코드
1. Subscribe 이용
button.rx.tap
.subscribe(onNext: { [weak self] _ in
self?.label.text = "안녕 반가워"
})
.disposed(by: disposeBag)
2. [weak self] 대신 withUnretained(self) 사용
button.rx.tap
.withUnretained(self)
.subscribe(onNext: { (vc, _) in
vc.label.text = "안녕 반가워"
})
.disposed(by: disposeBag)
3.
button.rx.tap
.map { }
.map { }
.map { } //여기까지는 글로벌쓰레드
.observe(on: MainScheduler.instance) //이후의 구독하는 것에 대해서는 메인스레드에서 동작하게끔
.map { }//여기부터는 위에서 메인스레드로 지정했으므로 메인스레드
.map { }
.map { }
.subscribe(onNext: { [weak self] _ in
self?.label.text = "안녕 반가워"
})
.disposed(by: disposeBag)
button.rx.tap
.observe(on: MainScheduler.instance)
.subscribe(onNext: { [weak self] _ in
self?.label.text = "안녕 반가워"
})
.disposed(by: disposeBag)
observe(on:) 메서드를 이용해 글로벌 쓰레드에서 동작하던 것을 메인 쓰레드에서 동작하게 바꿀 수 있음.
예를 들어, observe이전까지는 글로벌에서 동작하고 이후에 UI를 바꾸는 등의 코드를 작성할때는 observe를 이용해 메인스레드에서 진행되게함.
4. bind사용
button.rx.tap
.bind { [weak self] _ in
self?.label.text = "안녕 반가워"
}
.disposed(by: disposeBag)
bind는 Subscribe와 유사하지만 MainSchedular의 동작과 error이벤트를 방출하지 않음.
-> 그래서 보통 UI쪽을 다룰 때는 bind를 사용하는듯
5. map 오퍼레이터를 이용해 데이터의 흐름을 조작할 수 있음.
button
.rx
.tap
.map { "안녕 반가워" }
.bind(to: label.rx.text)
.disposed(by: disposeBag)
tap의 ControlEvent<Void>를 map을 이용해 String타입으로 변경해주면, 간단하게 bind할 수 있음
이 경우엔 self도 쓰지 않아도 됨
6. driver traits 사용
//6 driver traits: bind + stream 공유(리소스 낭비 방지, share())
button.rx.tap
.map { "안녕 반가워" }
.asDriver(onErrorJustReturn: "") //다른 타입으로 변경. 에러 발생할때 어떤 문자열을 쓸건지
.drive(label.rx.text)
.disposed(by: disposeBag)
이 경우엔 stream을 공유할 수 있어 리소스 낭비를 방지할 수 있다고함.
asDriver를 이용해서 driver타입으로 바꿔줌
driver는 메인 스레드에서의 실행을 보장함
Observable이 UI로 특화된 형태이므로 subscribe만 할 수 있고 값을 변경할 수는 없음.
drive는 내부적으로 share가 구현되어있음
정리하면, driver는 메인 스레드에서 사용되고 UI와 관련된 것에서 사용하면됨
-> Observable을 이용해서 observe를 이용해 스레드를 바꿔가며 사용해도되지만, 실수할 수도 있음
Share
일반적으로 Subscribe를 할 때마다 새로운 시퀀스가 생성됨
그래서 네트워크 요청같은 경우 share가 없다면 너무 많은 콜 수를 호출할 수도 있어 리소스가 낭비됨.
그래서 이러한 경우에에 share를 이용해 subscribe를 공유할 수 있게 처리함.
다시 말하지만 drive는 내부적으로 share가 구현되어있음.
'TIL' 카테고리의 다른 글
[TIL] 2022 / 11 / 1 (0) | 2022.11.01 |
---|---|
[TIL] 2022 / 10 / 27 - Rx (0) | 2022.10.27 |
[TIL] 2022 / 10 / 25 - Rx (0) | 2022.10.25 |
[TIL] 2022 / 10 / 24 - Rx (0) | 2022.10.24 |
[TIL] 2022 / 10 / 13 - Realm Migration (1) | 2022.10.13 |
- Total
- Today
- Yesterday