[iOS/Swift] RxSwift에서 flatMap 사용 시 스트림 종료 문제와 해결 방법
2025. 4. 4. 14:54ㆍiOS/Library
728x90
반응형
🧸 문제
flatMap에서 에러 발생 시 스트림이 종료되는 현상
RxSwift에서 flatMap이나 flatMapLatest를 사용할 때, 내부 스트림에서 에러가 발생하면 전체 스트림이 종료되는 문제가 있다. 예를 들어, 아래 코드를 보자.
func transform(input: Input) -> Output {
let responseLogin = input.buttonDidTap
.do(onNext: { type in
print("🟢 OAuth 실행 시작: \(type)")
})
.withUnretained(self)
.flatMap { owner, type in
owner.oauthService.execute(type: type)
.asObservable() // Single → Observable 변환
}
.withUnretained(self)
.flatMap { owner, oauthToken in
owner.loginUseCase.execute(oauthToken: oauthToken)
.asObservable() // Single → Observable 변환
}
return Output(resultLogin: responseLogin)
}
위 코드를 보면 oauthService.execute(type:)나 loginUseCase.execute(oauthToken:)에서 에러가 발생하면 스트림이 종료되므로 이후 새로운 버튼 입력이 들어와도 실행되지 않는다. 즉, 한 번 에러가 발생하면 더 이상 로그인 요청을 보낼 수 없다.
이를 해결하려면 에러 발생 시 스트림을 종료하지 않고 유지하는 방법을 적용해야 한다.
🧸 해결 방법 1: catch를 사용하여 스트림 유지
RxSwift의 catch 연산자를 활용하면 에러가 발생해도 스트림을 종료하지 않고 유지할 수 있다.
✔️ 수정된 코드
func transform(input: Input) -> Output {
let responseLogin = input.buttonDidTap
.do(onNext: { type in
print("🟢 OAuth 실행 시작: \(type)")
})
.withUnretained(self)
.flatMap { owner, type in
owner.oauthService.execute(type: type)
.asObservable()
.catch { error in
print("❌ OAuth 실패: \(error)")
return Observable.empty() // 에러 발생 시 빈 Observable 반환
}
}
.withUnretained(self)
.flatMap { owner, oauthToken in
owner.loginUseCase.execute(oauthToken: oauthToken)
.asObservable()
.catch { error in
print("❌ 로그인 실패: \(error)")
return Observable.empty()
}
}
return Output(resultLogin: responseLogin)
}
- OAuthService나 LoginUseCase에서 에러가 발생해도 스트림이 종료되지 않음
- 버튼 클릭 시 계속해서 실행됨
- Observable.empty()를 반환하여 에러 발생 시에도 정상적인 스트림 흐름 유지
🧸 해결 방법 2: materialize()를 사용하여 에러를 이벤트로 처리
RxSwift의 materialize()를 사용하면 에러도 하나의 이벤트로 변환하여 스트림이 종료되지 않도록 처리할 수 있다.
✔️ 수정된 코드
func transform(input: Input) -> Output {
let responseLogin = input.buttonDidTap
.do(onNext: { type in
print("🟢 OAuth 실행 시작: \(type)")
})
.withUnretained(self)
.flatMap { owner, type in
owner.oauthService.execute(type: type)
.asObservable()
.materialize() // ✅ 에러 발생해도 스트림 종료 X
}
.filter { !$0.isStopEvent } // ✅ 완료 이벤트 제거
.dematerialize() // ✅ 다시 원래 스트림으로 변환
.withUnretained(self)
.flatMap { owner, oauthToken in
owner.loginUseCase.execute(oauthToken: oauthToken)
.asObservable()
.materialize()
}
.filter { !$0.isStopEvent }
.dematerialize()
return Output(resultLogin: responseLogin)
}
- materialize()를 사용하여 에러를 이벤트로 변환 → 스트림이 종료되지 않음
- filter { !$0.isStopEvent }를 통해 완료 이벤트 제거
- dematerialize()로 다시 원래 데이터 스트림으로 변환
- 에러가 발생해도 스트림이 유지되므로 버튼 클릭 시 계속해서 실행됨
📂 정리
RxSwift에서 flatMap을 사용할 때 내부 스트림에서 에러가 발생하면 전체 스트림이 종료되는 문제가 발생한다. 이를 방지하기 위해 두 가지 해결 방법을 적용할 수 있다.
- catch를 사용하여 에러 발생 시 Observable.empty() 반환 → 스트림 유지
- materialize()를 사용하여 에러를 이벤트로 처리 → 스트림 종료 방지
이 두 가지 방법을 활용하면 RxSwift의 스트림을 안전하게 유지하면서도 원하는 동작을 구현할 수 있다.
728x90
반응형
728x90
반응형
'iOS > Library' 카테고리의 다른 글
[iOS/Swift] RxSwift 기본 개념 (0) | 2023.03.05 |
---|---|
[iOS/Swift] pod 설치방법 (0) | 2023.02.28 |