본문 바로가기
감정일기(가칭)

📘 diariesPublisher vs fetchDiaryByDay

by 밤새는 탐험가89 2025. 12. 16.
728x90
SMALL

LemonLog에서 Store API를 설계한 이유

LemonLog에서는 감정일기를 CoreData에 저장하고,
DiaryStore를 통해 ViewModel이 데이터를 접근하도록 설계했다.

이 과정에서 다음 두 가지 API가 자연스럽게 등장했다.

var diariesPublisher: AnyPublisher<[EmotionDiaryModel], Never>
func fetchDiaryByDay(from date: Date) -> [EmotionDiaryModel]
 

처음에는 이런 의문이 들었다.

“이미 diariesPublisher가 전체 감정일기를 계속 송출하고 있는데,
굳이 날짜 기반으로 조회하는 fetchDiaryByDay가 또 필요할까?”

 

이 글은 그 질문에 대한 답을 정리한 것이다.

 

1️⃣ diariesPublisher는 무엇을 위한 API인가?

diariesPublisher는 Store가 가진 전체 감정일기의 변화 스트림이다.

  • 새 일기 작성
  • 기존 일기 수정
  • 일기 삭제

이 중 어떤 일이 발생하든,
Store는 변경된 전체 일기 배열을 다시 송출한다.

store.diariesPublisher
    .sink { diaries in
        // 항상 최신 상태의 전체 일기
    }

 

핵심 포인트

diariesPublisher는 “확인용”이 아니라
“화면을 계속 최신 상태로 유지하기 위한 스트림”이다.

 

2️⃣ 날짜별 일기 화면에서 diariesPublisher를 사용하는 이유

날짜를 선택했을 때 보여주는 “일기 리스트 화면”은
반응형 UI가 필요한 대표적인 화면이다.

  • 다른 화면에서 일기를 삭제해도
  • 편집 후 돌아와도
  • 새로 작성해도

👉 리스트 화면은 자동으로 최신 상태를 반영해야 한다.

그래서 DiaryListViewModel에서는
diariesPublisher를 구독하고, 날짜만 필터링한다.

store.diariesPublisher
    .map { diaries in
        diaries.filter { $0.createdAt.isSameDay(as: selectedDate) }
    }
    .assign(to: &$diaries)

 

이 구조에서는:

  • 추가 fetch ❌
  • 재요청 ❌
  • 수동 갱신 ❌

Publisher 하나로 화면 상태가 완전히 유지된다.

 

3️⃣ 그렇다면 fetchDiaryByDay(from:)는 필요 없는가?

결론부터 말하면:

❌ 리스트 화면에서는 필요 없다
✅ 앱 전체 구조에서는 역할이 다르다

fetchDiaryByDay(from:)는 Reactive API가 아니다.
이 함수는 Query(조회) API다.

 

4️⃣ 두 API의 역할 차이

구분 diariesPublisher fetchDiaryByDay(from:)
성격 Reactive Stream Synchronous Query
자동 갱신
사용 대상 화면(ViewModel) 판단 / 계산 로직
변경 반영 자동 수동 재호출 필요
목적 UI 상태 유지 조건 확인

 

5️⃣ fetchDiaryByDay(from:)는 언제 쓰는가?

✅ 1. 즉시 판단이 필요한 경우

func hasDiary(on date: Date) -> Bool {
    !store.fetchDiaryByDay(from: date).isEmpty
}
  • 달력에서 점 표시 여부
  • “이 날 일기 있음 / 없음” 판단
  • Combine 스트림이 필요 없는 로직

✅ 2. 단발성 조회가 필요한 경우

  • 앱 시작 시 오늘 일기 존재 여부 확인
  • 특정 날짜에 대한 조건 계산

✅ 3. 테스트 코드

let result = store.fetchDiaryByDay(from: date)
XCTAssertEqual(result.count, 2)

 

Publisher 없이도
명확하고 단순한 테스트가 가능하다.

 

6️⃣ 자주 하는 오해 (중요)

❌ “수정 / 삭제 / 생성 시 확실하게 하기 위해
fetchDiaryByDay를 다시 호출해야 한다”

이건 잘못된 이해다.

  • 수정 / 삭제 / 생성 발생
  • Store 내부 데이터 변경
  • diariesPublisher가 자동으로 새 값을 송출
  • ViewModel이 즉시 반영

👉 Reactive 화면에서는 fetch 함수가 필요 없다.

 

 

7️⃣ LemonLog에서 선택한 기준

📌 화면(ViewModel)

  • 항상 diariesPublisher 사용
  • 화면 상태를 반응형으로 유지

📌 판단 / 계산 / 유무 체크

  • fetchDiaryByDay(from:) 사용
  • 단순하고 명확한 조회

 

8️⃣ 이 설계의 핵심 원칙

Store는 “데이터 접근 방법”을 제공하고
ViewModel은 “화면에 맞는 데이터 형태”를 만든다

  • Store는 똑똑해지지 않는다
  • ViewModel이 해석한다
  • 화면은 자동으로 갱신된다

 

마무리

처음에는
“API가 중복된 것 아닌가?”라는 의문에서 시작했지만,

정리해보니 두 API는 경쟁 관계가 아니라 역할 분담이었다.

  • diariesPublisher → 반응형 UI를 위한 스트림
  • fetchDiaryByDay(from:) → 즉시 판단을 위한 조회

이 기준을 세우고 나니,
Store와 ViewModel의 경계가 훨씬 명확해졌다.

728x90
LIST