Skip to content

Conversation

@JinUng41
Copy link
Collaborator

@JinUng41 JinUng41 commented Oct 24, 2025

👻 PULL REQUEST

📄 작업 내용

  • 소식 탭 큐레이션에 배지 기능을 구현했습니다.
  • 소식 탭 공지사항에 배지 기능을 구현했습니다.
  • 프로필 탭에 코디네이터 패턴을 적용하였습니다.
  • 계정 삭제 시, 해당하는 로컬 정보를 지우도록 하였습니다.
구현 내용 iPhone 13 mini
배지 조회
앱 재시작 후 조회
계정 스위칭 후 조회
탈퇴(코디네이터)
앱 삭제 후 조회

💻 주요 코드 설명

📌 UserSession, UserActivity

  • 유저 활동 데이터를 별도의 UserActivity로 분리하여 구현하였습니다.

관심사의 분리

  • UserSession은 계정 정보 등 핵심 정보를 관리하는 반면 유저 활동 기록에 해당하는 내용을 다루려 했기 때문에 빈도와 중요도가 다르다고 생각했습니다.
  • 모든 데이터를 한 곳에서 관리하면, 모델이 너무 많은 책임을 갖게 되고 불필요하게 비대해집니다.
  • 저는 이를 분리함으로써 각자의 역할에만 집중하는 더 작고 관리하기 쉬운 모델을 유지하도록 하였습니다.

독립적인 확장성 확보

  • 분리된 구조는 향후 새로운 기능이 추가될 때 큰 이점을 가집니다.
  • 예를 들어, 유저가 마지막으로 확인한 공지사항 시간이라고 한다면,
    • UserSession에 추가하는 것은 해당 모델에 의존하는 모든 코드에 영향을 미칠 수 있습니다.
      • 모델의 변경으로 인해 수정 범위가 넓어집니다.
    • 분리된 구조를 사용한다면, UserActivity 모델과 관련된 부분만 수정하면 되어, 앱의 인증 로직 등에 영향을 주지 않을 것입니다.
      • 변경의 범위를 최소화하여 안전하고 빠르게 기능을 확장해 나갈 수 있습니다.

커스텀 Codable 구현

  • UserActivity를 개발해 나가는 과정에서, 저는 초기에 큐레이션 아이디에 대해서만 다루었습니다.
  • 나중에 공지사항 개수를 추가하면서, 이전에 저장된 데이터와의 호환성 유지가 필요해졌습니다.
  • 옵셔널로 처리할 수 있었지만, 이후 사용하는 곳에서 옵셔널을 처리해야 하는 불편함을 야기합니다.
  • 따라서 저는 커스텀을 구현하여 키가 존재하지 않으면 기본적으로 .zero를 할당하도록 하였습니다.
    • 이를 통해 데이터의 버전 차이가 발생하더라도 모델의 프로퍼티를 non-optional로 유지할 수 있습니다.
👉🏼 UserActivity 코드
// UserSession.swift

struct UserActivity {
    static let `default` = UserActivity(lastViewedCurationID: 0, lastViewedNoticeCount: 0)

    var lastViewedCurationID: UInt
    var lastViewedNoticeCount: UInt
}

extension UserActivity: Codable {
    enum CodingKeys: CodingKey {
        case lastViewedCurationID, lastViewedNoticeCount
    }
    
    init(from decoder: any Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        
        self.lastViewedCurationID = try container.decode(UInt.self, forKey: .lastViewedCurationID)
        self.lastViewedNoticeCount = try container.decodeIfPresent(UInt.self, forKey: .lastViewedNoticeCount) ?? .zero
    }
    
    func encode(to encoder: any Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        
        try container.encode(self.lastViewedCurationID, forKey: .lastViewedCurationID)
        try container.encode(self.lastViewedNoticeCount, forKey: .lastViewedNoticeCount)
    }
}

📌 계정 삭제(탈퇴) 시 대응

코디네이터 패턴 적용

  • MyProfileView부터 시작되는 프로필 탭에 대해서 코디네이터 패턴을 적용하였습니다.
    • 유진님의 기존 코디네이터를 참고하여 비교적 쉽게 구현할 수 있었습니다. 감사합니다~
  • 모든 코디네이터 액션은 클로저를 통해 주입하였습니다.

계정 삭제 시 대응

  • 계정 삭제 시, 부가적으로 따라와야 하는 작업들을 순차 처리하도록 하였습니다.
    1. 유저 활동 정보(UserActivity) 삭제하기
    2. 유저 세션(UserSession) 삭제하기
  • 계정 삭제 요청을 보내어 성공하면, 유저 활동 정보를 삭제하고, 성공하면 유저 세션을 삭제하는 순서를 유지하도록 하였습니다.
    • 그 이유는 유저 활동 정보는 활성 유저 아이디(로그인된 유저 아이디)에 기반하기 때문입니다.
    • 따라서 유저 활동 정보를 먼저 삭제하고, 유저 세션을 삭제하도록 하였습니다.
  • 로그아웃 과정에서는 유저 활동 정보를 따로 삭제하지 않습니다.
    • 유저 세션의 활성 유저 아이디에 기반하기 때문입니다.
    • 로그아웃 시 유저 세션은 삭제되고 로그인하면 다시 재설정되기 때문입니다.

👀 리뷰어에게 전달할 사항

  • PR 단위가 너무 커진 점 깊이 반성합니다.
  • 하, 제가 300번째 이슈라니

✅ 이번 PR에서 이런 부분을 중점적으로 체크해주세요!

잠깐 확인하고 갈까요?
  • 들여쓰기를 5번 이하로 준수했는지, 코드 가독성이 적절한지 확인해주세요.

  • 한 줄당 120자 제한을 준수했는지 확인해주세요.

  • MARK 주석이 정해진 순서와 형식에 맞게 작성되었는지 확인해주세요.

  • 반복되는 상수 값이 있는지, 있다면 Constant enum으로 분리되어 있는지 확인해주세요.

  • 삼항 연산자가 길어질 경우 적절히 개행되어 있는지 확인해주세요.

  • 조건문에서 중괄호가 올바르게 사용되었는지 확인해주세요.

  • 라이브러리 import가 퍼스트파티와 서드파티로 구분되고 알파벳순으로 정렬되었는지 확인해주세요.

  • 용량이 큰 리소스나 호출되지 않을 가능성이 있는 프로퍼티에 lazy var가 적절히 사용되었는지 확인해주세요.

  • 메모리 누수 방지를 위한 weak 참조가 필요한 곳에 적용되었는지 확인해주세요.

  • 도메인 로직과 UI 로직이 적절히 분리되어 있는지 확인해주세요.

🔗 연결된 이슈

@JinUng41 JinUng41 requested a review from youz2me October 24, 2025 20:24
@JinUng41 JinUng41 self-assigned this Oct 24, 2025
@JinUng41 JinUng41 added ✨ feat 기능 또는 객체 구현 🛠️ fix 기능적 버그나 오류 해결 시 사용 ♻️ refactor 기존 코드를 리팩토링하거나 수정하는 등 사용 (생산적인 경우) 🍻 진웅 술 한잔 가온나~ labels Oct 24, 2025
@JinUng41 JinUng41 requested review from Copilot and removed request for Copilot October 24, 2025 20:32
- 사용하지 않는 코드 삭제
- 중복 코드 제거
Copy link
Member

@youz2me youz2me left a comment

Choose a reason for hiding this comment

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

고생하셨습니다!

Comment on lines +29 to +30
@Injected private var userSessionRepository: UserSessionRepository
@Injected private var userActivityRepository: UserActivityRepository
Copy link
Member

Choose a reason for hiding this comment

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

UserSession과 UserActivity의 범위가 모호할수도 있겠다는 생각이 드네요. 구현해두신 UserActivity 대로라면 UserSession의 notificationCount도 UserActivity로 옮겨야 할 것 같긴 한데... QA 이후에 해당 부분에 대해 조금 더 자세히 이야기해보고 리팩토링하면 좋을 것 같습니다.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

네 좋습니다!!

Comment on lines +138 to +139
func setupViewControllers() {
let useCase = viewModel.useCase
Copy link
Member

Choose a reason for hiding this comment

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

이 부분은 DIP를 위반할 수 있지 않을까요??

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

어떤 부분에서 위반한다고 말씀하신 것인지는 모르겠으나, 하나의 인스턴스를 전부 프로토콜 타입으로 주입되기 때문에 리소스 절약 및 DIP를 준수하고 있다고 생각됩니다

@github-project-automation github-project-automation bot moved this to In Review in Wable-iOS Oct 26, 2025
youz2me and others added 27 commits October 26, 2025 16:08
- QuizCoordinator 사용하지 않는 메서드 주석 처리
- Xcode 프로젝트 파일 업데이트
- checkTodayQuizCompletion 메서드 추가
- fetchActiveUserSession으로 사용자별 퀴즈 완료 여부 확인
- 퀴즈 완료 시 NextQuizInfoViewController, 미완료 시 QuizViewController 표시
- QuizCoordinator 사용하지 않는 메서드 주석 처리
- Xcode 프로젝트 파일 업데이트
- checkTodayQuizCompletion 메서드 추가
- fetchActiveUserSession으로 사용자별 퀴즈 완료 여부 확인
- 퀴즈 완료 시 NextQuizInfoViewController, 미완료 시 QuizViewController 표시
@youz2me youz2me merged commit 2415a08 into develop Oct 26, 2025
@github-project-automation github-project-automation bot moved this from In Review to Done in Wable-iOS Oct 26, 2025
@youz2me youz2me deleted the feat/#300-overview-badge branch October 26, 2025 08:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨ feat 기능 또는 객체 구현 🛠️ fix 기능적 버그나 오류 해결 시 사용 ♻️ refactor 기존 코드를 리팩토링하거나 수정하는 등 사용 (생산적인 경우) 🍻 진웅 술 한잔 가온나~

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

[Feat] 소식 탭 배지 구현

3 participants