Merged
Conversation
JinUng41
reviewed
Feb 27, 2025
Contributor
JinUng41
left a comment
There was a problem hiding this comment.
좋은 코드 감사합니다.
다만 기존의 Rx 코드에서도 가능하지 않나 싶어서 코멘트를 남겨봅니다.
debounce로 요청을 무시하거나 혹은, removeDuplicates로 중복되는 이벤트는 무시하게 하거나, take(1)을 이용하여 1회만 이벤트를 수신하는 방법으로도 가능할 것 같습니다만 어떻게 생각하실까요?
Member
Author
|
@JinUng41 하지만 지금 구현은 현재 옵저버블 객체를 최대한 변경하지 않고 (Rx로 리팩토링하지 않고) 작업한 내용이기에 그부분을 중점적으로 봐주시면 좋을것 같습니다! 물론,, 커스텀이 너무 많아져서 Rx로의 전환이 좀더 올바른 방향이였을수도 있다는 생각이 드네요ㅋㅋㅋ |
youz2me
approved these changes
Mar 1, 2025
Member
youz2me
left a comment
There was a problem hiding this comment.
굿~ 친절한 PR 감사드립니다. 상태 관리를 조금 더 효율적으로 해볼 수 있을 것 같아요.
저도 조만간 로그인 로직 구현해야 하는데 코드 참고해서 열심히 해보겠습니다 ... 감사합니다!
Comment on lines
-2231
to
+2237
| "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; | ||
| CODE_SIGN_STYLE = Manual; | ||
| CODE_SIGN_STYLE = Automatic; | ||
| CURRENT_PROJECT_VERSION = 1; | ||
| DEVELOPMENT_TEAM = ""; | ||
| "DEVELOPMENT_TEAM[sdk=iphoneos*]" = D2DRA3F792; | ||
| DEVELOPMENT_TEAM = D2DRA3F792; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🔗 연결된 이슈
📄 작업 내용
기능 내용이기에 GIF는 생략합니다
💻 About Pulse
문제발생
현재 로그인 기준으로, 앱 첫 설치후 첫 로그인 / 회원가입 버튼을 클릭시 네트워크 response가 약간 딜레이되고있는 상황입니다. 현재 이 지연중 로그인 버튼을 여러번 누르게 되었을때 동일한 API가 두번 사용되는 문제가 있었습니다. (Error Alert도 중복으로 날아오는 문제 발생)
현재 옵저버블 객체로 사용하고있는 해당 문제 대신, Rxswift를 사용하여 해당 문제를 해결하려 했습니다.
RxSwift 적용 고민
초기에는 RxSwift를 활용하여 이 문제를 해결하고자 했습니다만
PublishRelay는 지속적인 이벤트 스트림에 최적화되어 있어, 로그인과 같은 단일 이벤트 처리에는 적합하지 않았습니다.BehaviorSubject나ReplaySubject는 이벤트 값을 캐싱할 수 있지만, 완료 후에는 새로운 구독이 불가능하다는 제약이 있었습니다. 특히 로그인 후 화면 전환 과정에서 새로운 컨트롤러가 이전 이벤트 결과에 접근해야 하는 상황에서 문제가 되었습니다.Pulse 도입
이러한 제약을 해결하기 위해 ReactorKit의 Pulse 개념에서 영감을 얻은 커스텀 코드를 사용하게 되었습니다.
(공부하는 김에 도입한것도 물론 있습니다,,ㅎㅎ)
isConsumed플래그를 통해 중복 API 호출 문제를 효과적으로 해결했습니다.Pulse란?
지속적인 상태로 유지되어야 하는 데이터와 단 한 번만 발생해야 하는 이벤트를 구분하는 방법을 위해 사용됩니다.
Pulse는 일회성 이벤트를 처리하기 위해 설계된 메커니즘입니다.ReactorKit 프레임워크에서는
@Pulse프로퍼티 래퍼로 구현되어 있으며, 이는 특정 상태 값이 변경될 때만 옵저버가 트리거되도록 합니다.ReactorKit과 같은 구조화된 아키텍처에서는 일반적으로 상태(state)를 단일 진실의 원천(single source of truth)으로 관리하게 되는데, 모든 UI 관련 이벤트가 지속적인 상태로 취급되어야 하는 것은 아닙니다.
알림, 경고, 네비게이션 트리거, 오류 메시지와 같은 이벤트는 한 번만 발생해야 하며, 뷰가 다시 로드되거나 애플리케이션 상태가 변경될 때 반복되어서는 안 됩니다.
Pulse는 이러한 일회성 이벤트를 지속적인 상태 관리 시스템과 별도로 발행하고 소비하는 인스턴스를 제공해서 문제를 해결해버립니다람쥐
Pulse의 작동 방식
Pulse의 가장 기본적인 특징은 한 번만 소비(consume once) 동작입니다. Pulse를 통해 이벤트가 발행되면, 이 이벤트는 리스너에게 전달되지만 단 한 번만 발생합니다. 이는
isConsumed플래그를 통해 구현되며, 이벤트가 한 번 발생한 후에는 추가 이벤트 발행이 차단됩니다.또 다른 중요한 특징은 이벤트 캐싱입니다. Pulse는 발행된 이벤트 값을 저장하고, 나중에 리스너가 등록되면 이미 소비된 이벤트라도 해당 값을 전달합니다. 이는 화면 전환 후에도 이전 이벤트 결과에 접근해야 하는 경우에 특히 유용합니다.
ReactorKit에서의 @Pulse
(모두가 Rx를 알고있으니,,,자세한 코드 설명은 빼겟습니다)
ReactorKit 프레임워크에서
@Pulse는 프로퍼티 래퍼로 구현되어 있으며, 특정 상태 값이 변경될 때만 옵저버가 트리거되도록 합니다:일반 상태 변수와 달리,
@Pulse로 표시된 변수는 이 값이 변경될 때만 구독자에게 알림을 보냅니다. 이는 불필요한 UI 업데이트를 방지하고, 일회성 이벤트 처리를 단순화합니다.실사용하는 경우
Pulse는 다음과 같은 상황에서 특히 유용합니다:
RxSwift vs Pulse
RxSwift와Pulse의 일회성 이벤트 처리에는 몇 가지 한계가 있습니다:
반면 Pulse는 일회성 이벤트 처리를 위해 특별히 설계되었으며, 이벤트가 한 번만 발생하도록 보장하면서도 필요한 경우 값을 캐싱하고 전달할 수 있습니다.
결론
Pulse는 일회성 이벤트와 지속적인 상태를 명확하게 구분하여 관리할 수 있는 강력한 도구이다!
코드설명
현재 리뷰하시면서 이해하기 편하도록 기본 주석과 describtion을 많이 작성해두었는데 이부분은 코드리뷰 이후 삭제하도록 하겟습니다.
1. Pulse 클래스
isConsumed플래그를 통해 이벤트가 단 한 번만 발생하도록 보장합니다.2. LoginViewModel에서의 Pulse 활용
LoginViewModel.swift에서는 세 가지 Pulse 인스턴스를 사용하여 각기 다른 유형의 일회성 이벤트를 처리합니다이 인스턴스들을 통해
errorPulse에서 에러 메시지가 발생하면 자동으로navigationPulse를 통해 오류 알림 화면으로 네비게이션하도록 합니다. 즉, 두 이벤트 스트림을 연결해줍니다.로그인 성공 후
navigationPulse = Pulse<LoginNavigation>()로 Pulse 객체를 재설정하는 부분입니다. 이는 이전의 네비게이션 이벤트를 초기화하고 새로운 이벤트만 처리하도록 보장합니다.3. LoginViewController에서 Pulse 구독
LoginViewController.swift에서는 ViewModel의 Pulse 이벤트를 구독하여 UI 업데이트와 화면 전환을 처리합니다isNavigating플래그를 사용하여 중복 네비게이션을 방지합니다.4. SceneDelegate에서의 Pulse 활용
SceneDelegate.swift에서도 LoginViewModel의 navigationPulse를 구독하여 화면 전환을 합니다.자동로그인 코드를 여기서 실행합니다.
5. 버튼 중복 클릭 문제 해결
가장 큰 문제였던 중복 로그인호출 문제를 해결한 과정입니다.
LoginViewModel에서:
이 코드 자체에는 중복 클릭 방지 로직이 없지만, Pulse의
isConsumed플래그를 통해 동일한 API 호출이 여러 번 발생하더라도 네비게이션 이벤트는 한 번만 처리됩니다.LoginViewController에서:
여기서는
isNavigating플래그를 추가로 사용하여 UI 레벨에서도 중복 네비게이션을 방지합니다.참고한곳
https://github.com/ReactorKit/ReactorKit/blob/master/Sources/ReactorKit/Pulse.swift
👀 기타 더 이야기해볼 점
ReactorKit의 정확한 이해와 Pulse의 정확한 이해가 저도 많이 부족합니다만 열심히 해보았습니다 매서운 코드리뷰 부탁드리고 이해가 안가거나 질문 있으시다면 남겨주세요 제가 모르는 부분일수 있는데 같이 공부해 보아요!