-
Notifications
You must be signed in to change notification settings - Fork 15
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] #392 - 솝마디 결과 뷰, 부적 화면 전환 및 데이터 바인딩 #394
[Feat] #392 - 솝마디 결과 뷰, 부적 화면 전환 및 데이터 바인딩 #394
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.
덕분에 많이 배워갑니다 !! 감사해요
@@ -24,4 +24,18 @@ public extension UIColor { | |||
blue: rgb & 0xFF | |||
) | |||
} | |||
|
|||
convenience init(hex: String) { |
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.
👍👍
self?.router.dismissModule(animated: true) | ||
self?.finishFlow?() |
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.
guard let으로 self 한 번 확인해주세요 !
public final class DailySoptuneCoordinator: DefaultCoordinator { | ||
public final class DailySoptuneResultCoordinator: DefaultCoordinator { |
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.
ㅌㅋㅋㅋㅋ죄송합니다 .. 🫶
rootController = dailySoptuneResult.vc.asNavigationController | ||
router.present(rootController, animated: false, modalPresentationSytle: .overFullScreen) |
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.
이 부분 저는 viewcontrollable까지만 전달했는데 asNavigationController로 지정해주신 이유가 있을까요?
개인적인 생각으로는 main에서는 새 내비게이션이 시작하니까 showDailySoptuneMain에서는 asNavigationController가 맞는 것 같고 result랑 card에서는 viewControllable만 넘겨주는 것이 맞는 것 같습니다 !
근데 vc를 넘겨주는 것과 vc.viewControllable의 차이를 잘 모르겠어요. . . @lsj8706 혹시 설명해주실 수 있나요 ? 선배님 ..
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.
dailySoptuneResult.vc
를 present를 띄우고 있는데, 만약 이 vc위에 다른 vc를 push 해야 한다는 니즈가 있다면, 지금처럼 asNavigationController
사용해서 네비게이션 컨트롤러로 만들어서 올려야해요.
이런 니즈가 없다면 그냥 viewControllable
상태로 올려도 무방해요!
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.
아하!!! 감사합니다
.withUnretained(self) | ||
.sink { _, cardModel in | ||
self.onReceiveTodaysFortuneCardButtonTapped?(cardModel) | ||
output.todaysFortuneCard.send(cardModel) |
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.
ResultViewController에서 output을 사용하지 않기 때문에 필요없는 코드라고 생각합니다 .. !
let coordinator = DailySoptuneResultCoordinator( | ||
router: router, | ||
factory: DailySoptuneBuilder(), | ||
pokeFactory: PokeBuilder() |
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.
배워갑니다👍
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.
고생하셨어요~! 윤서가 질문 남긴거 답변하려고 들어왔다가 눈에 보이는거 몇가지만 코멘트 남겨둬요.
추가로~ 제 의견 또는 팀원들의 코멘트를 무조건 수용하는 것 보다는 스스로 고민해보고 팀원들과 논의도 많이 해보는 시간을 가지셨으면 좋겠네요! (물론 데드라인 때문에 바쁘면 불가능)
private let factory: DailySoptuneFeatureBuildable | ||
private let router: Router | ||
|
||
private let cardModel: DailySoptuneCardModel |
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.
질문!
현재 요구사항과 뷰 구조를 제가 잘 몰라서 생긴 질문인데요~!
cardModel을 Coordinator가 속성으로 들고 있지 않고 start()의 파라미터로 받게 하는건 어려울까요!?
지금도 크게 문제될 것은 없지만 코디네이터가 굳이 이런 도메인 상태를 가져야 하는가 하는 짧은 생각이 들어서요~ ㅎㅎ
public override func start(cardModel: DailySoptuneCardModel) {
showDailySoptuneCard(cardModel: DailySoptuneCardModel)
}
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.
헉 ... 이 부분 논의해보고 수정하겠습니다 ...ㅇ.ㅇ
dailySoptuneCardCoordinator.start() | ||
} | ||
|
||
private func showMessageBottomSheet(userModel: PokeUserModel, on view: UIViewController?) -> AnyPublisher<(PokeUserModel, PokeMessageModel, isAnonymous: Bool), Never> { |
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.
이건 그냥 제가 예전에 쌓아둔 개인적인 아쉬움인데 공유차 남겨요.
현재는 바텀 시트를 보여주고 이 바텀시트에서 사용자가 선택한 데이터들을 Publisher 형태로 제공하고 있는데 이걸 바텀 시트를 띄우는 메서드인 showMessageBottomSheet()
의 리턴값으로 바로 반환하니까 이 함수를 처음 보는 사람 입장에서는 showMessageBottomSheet()
는 왜 (PokeUserModel, PokeMessageModel, isAnonymous: Bool)
이런 값들을 반환하는거지? 이 값들은 뭘까 하는 의문이 생길 수 있다고 봐요. 함수명은 그저 바텀 시트를 show 한다고만 알려주는데 뭔가를 리턴하고 이 리턴 값의 정체가 불분명 하니까요.
그래서 이런 바텀 시트류의 UI에서는 콜백 인터페이스가 Publisher나 클로저가 아닌 Delegate 패턴이어야 더 명확하다고 생각해요. (예전에는 이런 개념이 없었어서 그냥 혼용했었음 😅)
예를 들어 이렇게 바뀌는 거에요.
private func showMessageBottomSheet(userModel: PokeUserModel, on view: UIViewController?) {
guard let bottomSheet = self.pokeFactory
.makePokeMessageTemplateBottomSheet(messageType: messageType)
// 생략
bottomSheet.delegate = self
// 생략
}
extension DailySoptuneResultCoordinator: MessageBottomSheetDelegate {
func messageBottomSheet(pickedMessage: PokeMessageModel) {} // 필요한 정보들 전달(축약 버전)
}
즉, 이벤트 전달을 위한 바인딩을 할 때 언제 클로저(또는 Publisher)를 쓸지 또는 Delegate를 쓰면 좋을지 상황에 맞게 잘 고민해보면 좋을 것 같아요. 각각 장단점이 있어요.
사실 여기서는 이미 publisher로 인터페이스가 맞춰져 있어서 그냥 이대로 가는게 최선이에요 ㅋㅋㅋ 그냥 공부할 때 도움되라고 남긴 코멘트입니당
|
||
public var viewModel: DailySoptuneCardViewModel | ||
private let cardModel: DailySoptuneCardModel | ||
private var cancelBag = CancelBag() |
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.
요거 private let
으로 바꿔도 될 것 같긴하네요
private extension DailySoptuneCardVC { | ||
func setData() { | ||
self.subCardLabel.text = cardModel.description | ||
self.cardLabel.text = "\(cardModel.name)이 왔솝" |
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.
아 ㅋㅋㅋ 왔솝이 의도된 워딩인거죠???ㅋㅋㅋㅋ
힙하네요 😆
input.goToHomeButtonTap | ||
.withUnretained(self) | ||
.sink { _ in | ||
self.onGoToHomeButtonTapped?() | ||
}.store(in: cancelBag) |
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.
이렇게 쓰면 withUnretained는 의미가 없을거에요.
withUnretained의 구현부를 보시면 self를 weak 참조 한다음에 리턴해주고 있어요. 이 리턴된 값을 사용해야 약한 참조가 유지돼요.
(그래서 개인 취향이지만 전 귀찮아서 [weak self] 쓰고 그냥 guard let이나 self?로 처리해요)
input.goToHomeButtonTap | |
.withUnretained(self) | |
.sink { _ in | |
self.onGoToHomeButtonTapped?() | |
}.store(in: cancelBag) | |
input.goToHomeButtonTap | |
.withUnretained(self) | |
.sink { owner in | |
owner.onGoToHomeButtonTapped?() // 여기서 owner가 self를 약한 참조한 변수 | |
}.store(in: cancelBag) |
🌴 PR 요약
🌱 작업한 브랜치
🌱 PR Point
📌 참고 사항
PokeFeature
의 BottomSheet을DailySoptuneFeature
모듈에서 사용하면서,DailySoptuneBuilder
에PokeFeature
를 import해 직접 생성하고 있었습니다. 따라서 모듈 간의 강한 결합이 이루어졌던 부분을 제거하고,ApplicationCoordinator
에서 PokeBuilder()를 주입하여 인터페이스를 통해PokeBuilder
에서 BottomSheet를 생성하도록 수정했습니다. (이 부분에 대해 잘못된 부분이 있다면 리뷰 부탁드립니다..!)📸 스크린샷
📮 관련 이슈