Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion SMASHING/Presentation/Home/HomeViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ final class HomeViewController: BaseViewController {

private var tooltipView: TooltipView?
private var tooltipDismissTap: UITapGestureRecognizer?
private var shouldRefreshAfterSportChange = false
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

스포츠 변경 완료를 Bool 플래그 하나로 추적하면 잘못된 프로필 응답에 반응할 수 있습니다.

myProfileFetched는 초기 로드/재진입/스포츠 변경 결과를 모두 타는 스트림인데, 지금 구조에서는 어떤 응답이 먼저 와도 shouldRefreshAfterSportChange == true면 홈을 새로고침합니다. 기존 .viewWillAppear 요청의 응답이 늦게 도착하면 변경 전 sport 기준으로 fetchHomeData()가 먼저 실행되고, 실제 sport 변경 완료 응답에서는 플래그가 이미 내려가 후속 갱신이 빠질 수 있습니다. Bool 대신 pending sport 값을 들고 있다가 response.activeProfile.sportCode와 일치할 때만 refresh 하도록 묶는 편이 안전합니다.

예시 방향
-    private var shouldRefreshAfterSportChange = false
+    private var pendingSportRefresh: Sports?

...
-                if self.shouldRefreshAfterSportChange {
-                    self.shouldRefreshAfterSportChange = false
+                if self.pendingSportRefresh == response.activeProfile.sportCode {
+                    self.pendingSportRefresh = nil
                     self.input.send(.viewWillAppear)
                 }

...
-                    self.shouldRefreshAfterSportChange = true
+                    self.pendingSportRefresh = sport
                     self.myProfileInput.send(.sportsCellTapped(sport))

Also applies to: 259-262, 639-640

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@SMASHING/Presentation/Home/HomeViewController.swift` at line 31, Replace the
Boolean flag shouldRefreshAfterSportChange with an optional pendingSportCode
(e.g., String?) and change the logic around where you set and consume that flag:
when initiating a sport change set pendingSportCode = newSportCode instead of
true; in the myProfileFetched response handler compare
response.activeProfile.sportCode to pendingSportCode and only call
fetchHomeData() and clear pendingSportCode when they match; ensure other code
paths (e.g., viewWillAppear responses) do not blindly refresh when
pendingSportCode is non-nil and clear pendingSportCode only after a successful
matching refresh.


override func loadView() {
view = rootView
Expand Down Expand Up @@ -255,6 +256,10 @@ final class HomeViewController: BaseViewController {
self.latestMyProfile = response
self.dropDownView?.configure(profile: response, myRegion: self.myRegion)
self.homeView.reloadSections(IndexSet(integer: HomeViewLayout.navigationBar.rawValue))
if self.shouldRefreshAfterSportChange {
self.shouldRefreshAfterSportChange = false
self.input.send(.viewWillAppear)
}
}
.store(in: &cancellables)
}
Expand Down Expand Up @@ -422,7 +427,9 @@ final class HomeViewController: BaseViewController {
UserDefaults.standard.set(address, forKey: UserDefaultKey.region)
self.userProfileService.updateRegion(region: address)
.receive(on: DispatchQueue.main)
.sink(receiveCompletion: { _ in }, receiveValue: { _ in })
.sink(receiveCompletion: { _ in }, receiveValue: { [weak self] _ in
self?.input.send(.viewWillAppear)
})
.store(in: &self.cancellables)
}
NavigationManager.shared.push(addressVC, hidesBottomBar: true)
Expand Down Expand Up @@ -629,6 +636,7 @@ extension HomeViewController {
dd.onSportsCellTapped = { [weak self] sport in
guard let self else { return }
if let sport {
self.shouldRefreshAfterSportChange = true
self.myProfileInput.send(.sportsCellTapped(sport))
} else {
self.input.send(.addSportsTapped)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ import Then
import SnapKit

final class MatchResultCardView: BaseUIView {
private var currentMyScore: Int = 0
private var currentRivalScore: Int = 0

private let containerView = UIView().then {
$0.backgroundColor = .Background.surface
Expand Down Expand Up @@ -41,23 +39,9 @@ final class MatchResultCardView: BaseUIView {
$0.textAlignment = .center
}

private let myScore = UILabel().then {
$0.text = "0"
$0.setPretendard(.headerHeroB)
$0.textColor = .Text.secondary
$0.textAlignment = .center
}

private let scoreSemicolon = UILabel().then {
$0.text = ":"
$0.setPretendard(.headerHeroB)
$0.textColor = .Text.secondary
$0.textAlignment = .center
}

private let rivalScore = UILabel().then {
$0.text = "0"
$0.setPretendard(.headerHeroB)
private let vsLabel = UILabel().then {
$0.text = "vs"
$0.setPretendard(.headerHeroSb)
$0.textColor = .Text.secondary
$0.textAlignment = .center
}
Expand Down Expand Up @@ -90,9 +74,7 @@ final class MatchResultCardView: BaseUIView {
myNickName,
rivalImage,
rivalNickName,
myScore,
scoreSemicolon,
rivalScore)
vsLabel)

addSubviews(containerView)
}
Expand Down Expand Up @@ -120,21 +102,11 @@ final class MatchResultCardView: BaseUIView {
$0.centerX.equalTo(myImage)
}

myScore.snp.makeConstraints {
$0.trailing.equalTo(scoreSemicolon.snp.leading).offset(-6)
$0.centerY.equalTo(scoreSemicolon)
}

scoreSemicolon.snp.makeConstraints {
vsLabel.snp.makeConstraints {
$0.centerX.equalToSuperview()
$0.centerY.equalTo(myImage)
}

rivalScore.snp.makeConstraints {
$0.leading.equalTo(scoreSemicolon.snp.trailing).offset(6)
$0.centerY.equalTo(scoreSemicolon)
}

rightCrownImageView.snp.makeConstraints {
$0.bottom.equalTo(rivalImage.snp.top).offset(2)
$0.centerX.equalTo(rivalImage)
Expand All @@ -155,29 +127,12 @@ final class MatchResultCardView: BaseUIView {

// MARK: UI Methods

// 텍스트 필드에서 받은 스코어로 CardView의 스코어 갱신하기
func updateScore(myScore: String, rivalScore: String) {
self.currentMyScore = Int(myScore) ?? 0
self.currentRivalScore = Int(rivalScore) ?? 0

self.myScore.text = myScore
self.rivalScore.text = rivalScore
}

// 드롭다운에서 선택한 승자에 왕관 씌우기
func updateWinnerCrown(isMyWin: Bool) {
leftCrownImageView.isHidden = !isMyWin
rightCrownImageView.isHidden = isMyWin
}

func getMyScore() -> Int {
return currentMyScore
}

func getRivalScore() -> Int {
return currentRivalScore
}

func configure(myName: String, myImage: UIImage?, rivalName: String, rivalImage: UIImage?) {
myNickName.text = myName
rivalNickName.text = rivalName
Expand Down