podoit 모의 면접

hyun·2025년 9월 9일
0

면접

목록 보기
4/4

mvvm이 뭐고 어떤 방식을 프로젝트에 대입했나요?

•	M(Model): 순수 데이터/비즈니스 객체. 저장·불러오기 로직은 Repository에서
•	V(View/Controller): 화면 그리는 쪽(UIKit에서는 UIView/UIViewController). 입력 이벤트를 받고, ViewModel의 출력만 바인딩해서 그려줌
•	VM(ViewModel): 화면에 필요한 상태/로직을 소유. 모델을 가공해 UI에서 바로 쓸 수 있는 형태로 내보내고, 사용자 입력을 받아 Repository를 통해 Model을 변경

프로젝트에서는

  • 파일 매핑
    • Model/Repository
    • TimerModel(SwiftData @Model)
    • SwiftDataManager : TimerRepository (CRUD 담당)
    • View (UIKit)
    • TimerViewController(리스트 화면), TimerEditViewController(편집 화면)
    • TimerCell, TimerHeaderView, EmptyStateView (UI 컴포넌트)
    • ViewModel
    • TimerEditViewModel (편집 상태·중복 검사·저장/수정 로직)
    • (통계 쪽은 StatsViewModel에서 Rx로 출력 제공)

역할 분리

  • ViewController
    • UI 레이아웃(SnapKit/Then), 버튼 탭/셀 선택 처리
    • 알럿/토스트 표시, 화면 전환(push/present)
    • ViewModel의 출력값 바인딩 + 이벤트를 입력으로 전달
    • ViewModel
    • 입력 상태(제목, 이모지, 목표시간 등) 보유
    • 유효성 검증(예: hasDuplicateTitle)
    • 저장/수정/삭제는 Repository 호출로 처리
    • UI가 바로 쓸 수 있는 가공값 제공(문구, 포맷팅, 버튼 활성화 등)

흐름

  • 타이머 추가
    1. TimerViewController의 “추가하기” 버튼 탭
    2. TimerEditViewController 표시(빈 상태의 TimerEditViewModel 주입)
    3. 사용자가 입력 → VC가 VM에 값 전달 (혹은 텍스트 변경 시 VM 바인딩)
    4. 저장 버튼 탭 → VC가 viewModel.save() 호출
    5. VM이 중복 검사 → 통과 시 TimerRepository.insert(...)
    6. 성공 콜백 → VC가 목록 리로드(또는 델리게이트/노티로 상위에 반영) → 닫기

  • 타이머 편집
    1. 리스트 셀 탭 → 편집 VC 표시(기존 엔티티 담긴 TimerEditViewModel(editing:) 주입)
    2. 기존 값 프리필(VC는 VM의 출력으로 UI 세팅)
    3. 수정 후 저장 → VM이 update(...) 호출 → 성공 시 VC가 스냅샷 갱신

  • 타이머 삭제
    1. 리스트에서 삭제 액션 → VC가 커스텀 알럿(PodoAlertController) 표시
    2. 확인 시 Repository의 delete(...) 호출(여긴 VC에서 직접 or VM 통해서 — 한 곳으로 일원화 권장)
    3. 성공 후 Diffable Snapshot 재적용 → 셀 사라짐

레포지토리가 뭐고 왜 사용하셨나요?

데이터 접근 로직(저장·조회·삭제 등)을 한 곳에 모아두는 계층.

Model(TimerModel 등)과 Persistence Layer(SwiftData, CoreData, Realm 등) 사이에서 중간 추상화 계층.
• ViewModel이나 ViewController는 데이터가 어디에/어떻게 저장되는지 몰라도 됨. 그냥 repo.fetchAll() 같은 API만 부르면 됨.

관심사 분리 때문에 사용
VC/VM은 데이터가 필요하다만 알면 되고, 저장 방식은 Repository가 책임
나중에 SwiftData → CoreData, Realm, CloudKit 등 바꿔도 VC/VM은 안 바뀜

레포지토리 말고도 프로젝트에서 객체지향적으로 처리한 게 있나요?

-> 의존성 주입
VC에서 직접 SwiftData 안 쓰고, 생성자에 TimerRepository를 주입.

init(repository: TimerRepository) {
  self.repository = repository
  super.init(nibName: nil, bundle: nil)
}

VC에서 직접 SwiftData 안 쓰고, 생성자에 TimerRepository를 주입한 이유가 무엇인가요?

-> 결합도 낮추기

  • 만약 VC가 SwiftData를 직접 쓴다면?
    → VC는 UI도 하고, DB 접근 코드도 다 알아야 함 → 강하게 결합됨
  • 지금처럼 VC가 TimerRepository 프로토콜만 의존하면
    VC는 저장/불러오기라는 역할만 알고, 구현이 SwiftData든, CoreData든, Realm이든, Mock이든 상관없음.

Rxswift에서 Observable이 무엇인가요?

시간에 따라 변하는 이벤트 스트림을 나타내는 객체
값이 생길 때마다(onNext), 에러가 날 때(onError), 끝날 때(onCompleted) 이벤트를 방출 옵저버(구독자)가 그걸 듣고 반응

CalendarView.swift

private let selectedDateRelay = BehaviorRelay<Date>(value: Date())
var selectedDate: Observable<Date> { selectedDateRelay.asObservable() }

뷰 내부에서 선택된 날짜 상태를 Relay로 관리.
외부에서는 selectedDate Observable을 구독해서 반응.

Relay랑 Subject 차이가 무엇인가요?

  • Subject
    - onNext, onError, onCompleted 모두 호출 가능
  • Relay
    - 에러/완료를 방출하지 않음

0개의 댓글