-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Feat] 자동로그인 Reactorkit - pulse 도입 #409
base: suyeon
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
좋은 코드 감사합니다.
다만 기존의 Rx 코드에서도 가능하지 않나 싶어서 코멘트를 남겨봅니다.
debounce
로 요청을 무시하거나 혹은, removeDuplicates
로 중복되는 이벤트는 무시하게 하거나, take(1)
을 이용하여 1회만 이벤트를 수신하는 방법으로도 가능할 것 같습니다만 어떻게 생각하실까요?
@JinUng41 하지만 지금 구현은 현재 옵저버블 객체를 최대한 변경하지 않고 (Rx로 리팩토링하지 않고) 작업한 내용이기에 그부분을 중점적으로 봐주시면 좋을것 같습니다! 물론,, 커스텀이 너무 많아져서 Rx로의 전환이 좀더 올바른 방향이였을수도 있다는 생각이 드네요ㅋㅋㅋ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
굿~ 친절한 PR 감사드립니다. 상태 관리를 조금 더 효율적으로 해볼 수 있을 것 같아요.
저도 조만간 로그인 로직 구현해야 하는데 코드 참고해서 열심히 해보겠습니다 ... 감사합니다!
"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; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
어이구 이거 왜 이렇게 됐지요
🔗 연결된 이슈
📄 작업 내용
기능 내용이기에 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의 정확한 이해가 저도 많이 부족합니다만 열심히 해보았습니다 매서운 코드리뷰 부탁드리고 이해가 안가거나 질문 있으시다면 남겨주세요 제가 모르는 부분일수 있는데 같이 공부해 보아요!