일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- RxSwift
- SwiftUI
- SWIFT
- URLSession
- QoS
- 컴공선배
- Main Thread
- distinctUntilChanged
- 개발블로그
- observe(on:)
- observable
- Xcode
- flatmap
- UIListContentConfiguration
- dispatchqueue
- alamofire
- ContentMode
- Moya
- interceptor
- ReactiveX
- iOS교육
- RxCocoa
- cellForRowAt
- UICollectionViewListCell
- RequestInterceptor
- restfulAPI
- IOS
- 라이징캠프
- defaultContentConfiguration
- UIKit
- Today
- Total
RB의 iOS 개발 이야기
Rx가 지원하는 스케줄러(schedulers)의 종류들 본문
이번 포스트는 바로 직전의 포스트의 다음 글로 내용이 이어집니다!
이전 포스트를 확인하고 넘어오시는 것을 추천드립니다 ㅎㅎ
Alamofire RequestInterceptor 사용해보기
로그인 같은 작업을 수행하게되면 대개 로그인 API에서 accessToken과 refreshToken을 반환하게된다. 이러한 토큰들은 앱 내의 여러 작업을 수행하는 API를 요청할 때에 필요한 값들인데 오늘은 회원탈
rb-ios.tistory.com
읽고 넘어오셨다면?
이어서 작성해보도록 하겠습니다.
Alamofire의 RequestInterceptor를 사용해보며 adapt와 retry 메서드에 코드를 작성했었습니다.
아래 코드를 보시면
func retry(_ request: Request, for session: Session, dueTo error: Error, completion: @escaping (RetryResult) -> Void) {
guard let response = request.task?.response as? HTTPURLResponse, response.statusCode == 419 else {
completion(.doNotRetryWithError(error))
return
}
let task = Observable.just(())
task
.observe(on: MainScheduler.asyncInstance)
.flatMap { _ in
self.repository.requestAccessToken()
}
.subscribe(onNext: { result in
switch result {
case .success(let data):
print(UserDefaultsManager.token)
UserDefaultsManager.token = data.token
completion(.retry)
case .failure(let error):
completion(.doNotRetryWithError(error))
}
})
.disposed(by: disposeBag)
}
.observe(on: MainScheduler.asyncInstance) 부분을 확인할 수 있는데요.
처음에는 이 코드를 작성하지 않았습니다. 그러나 작성하지 않고 retry 메서드가 실행되는 순간 런타임 에러가 발생하더군요!
어떤 에러인지를 확인해보니 main thread를 맞춰주어야 flatMap 내부의 self.repository.requestAccessToken() 메서드가 제대로 실행되는 것이었습니다.
retry 메서드가 실행되기 전과 후로 thread를 맞춰주어야만 런타임 에러가 발생하지 않고 잘 동작하게되는 것 같았습니다.
코드를 처음 작성했을 때는 여기까지 오는데 너무 많은 시간을 허비하여 동작만 확인하고 넘어갔었는데 생각해보니
네트워크 통신을 main Thread에서 수행하는게 맞을까라는 의문이 들었습니다.
그래서!
.observe(on:)에 관하여 검색을 시도해봤습니다!
Builtin schedulers
Rx는 모든 종류의 스케줄러를 쓸 수 있습니다.
만약 스케줄러가 시리얼한 것이 증명되면 추가적인 최적화도 적용이 가능합니다.
다음은 현재 지원하는 스케줄러들입니다.
위와 같은 설명을 확인할 수 있었고 또한 Rx에서 지원하는 모든 종류의 스케줄러는 찾아볼 수 있었습니다.
그 중에서 SerialDispatchQueueScheduler (Serial scheduler)을 찾을 수 있었다.
특정 dispatch_queue_t에서 실행되어야 하는 추상적인 작업에서 사용합니다.
컨커런트 디스패치 큐에 전달된 경우에도 시리얼 디스패치 큐로 변환됩니다.
시리얼 스케줄러는 observeOn를 위한 특정 최적화를 가능하게 해줍니다.
메인 스케줄러는 SerialDispatchQueueScheduler의 인스턴스 중 하나입니다.
윗말이 가장 핵심인 것 같다.
내가 처음에 사용했던 메인 스케줄러는 SerialDispatchQueueScheduler 인스턴스 중 하나였고 네트워크 처리에 알맞은 코드를 짜보자면 백그라운드로 돌리는게 맞을 것이다.
let task = Observable.just(())
task
.observe(on: SerialDispatchQueueScheduler.init(qos: .background))
.do {
print(Thread.isMainThread)
}
.flatMap { _ in
self.repository.requestAccessToken()
}
.do {
print(Thread.isMainThread)
}
.subscribe(onNext: { result in
switch result {
case .success(let data):
print(UserDefaultsManager.token)
UserDefaultsManager.token = data.token
completion(.retry)
case .failure(let error):
completion(.doNotRetryWithError(error))
}
})
.disposed(by: disposeBag)
위 코드는
.observe(on: SerialDispatchQueueScheduler.init(qos: .background))
SerialDispatchQueueScheduler로 지정해주었으며 qos도 .background로 지정해준 코드입니다.
그 아래로 .do 구문을 확인할 수 있는데요?
.do {
print(Thread.isMainThread) // True
}
.flatMap { _ in
self.repository.requestAccessToken()
}
.do {
print(Thread.isMainThread) // // True
}
do 구문 내부는 현재 thread가 main thread 인지를 확인하는 구문이며 bool 타입으로 결과를 반환합니다.
두 do 구문 모두 True가 출력되는 것을 확인할 수 있으며 main thread로 맞춰놓았기 때문에 런타임 에러도 발생하지 않음을 알 수 있습니다.
+ more) RequestInterceptor 글을 작성하며 알게된 지식이 많아... 다음 포스트에서 마지막 하나만 더 공유하겠습니다!
.observe(on: SerialDispatchQueueScheduler.init(qos: .background)) 에서 qos에 관한 마지막 정리로 interceptor 포스트는 마치도록 하겠습니다. 오늘도 읽어주셔서 감사합니다!
참고
[RxSwift] 스케줄러
[RxSwift] Schedulers
pilgwon.github.io
[Swift] DispatchQueue의 qos 사용하기
GCD에서 global큐나 커스텀 큐를 사용할 때 qos(quality of service)를 사용해 작업의 중요도를 결정할 수 있습니다. 그렇기 때문에 작업의 우선순위를 결정하기 위해서는 qos의 우선순위가 어떻게 되는지
dev-dmsgk.tistory.com
[Tayga 개발기] (3) - RxSwift를 통한 Moya 비동기 처리
저번 포스트에 이어서 Moya 타겟에 실제로 RxSwift를 통해 데이터를 읽어오겠습니다. 저번 포스트에서 만든 Endpoint로 이루어진 타겟 enum은 실제로는 아무 동작도 하지 않습니다. 그저 타겟 타입들을
leejigun.github.io
'iOS > RxSwift' 카테고리의 다른 글
Alamofire RequestInterceptor 사용해보기 (0) | 2023.12.14 |
---|---|
App Store 검색 예제 구현중 발생한 메모리 누수 이슈 (0) | 2023.11.28 |
Observable과 Subject의 차이는 무엇인가? (0) | 2023.10.27 |