🧩 1️⃣ AnyPublisher<[EmotionDiaryModel], Never> — 이 타입의 의미부터
AnyPublisher<Output, Failure> 는
Combine의 표준 Publisher 타입을 감싸는 “추상 타입(Wrapper)”이에요.
💬 쉽게 말해서:
“이 Publisher는 [EmotionDiaryModel]을 내보내고,
에러는 발생하지 않는다(Never)” 는 뜻이에요.
🧠 예를 들어보면
let publisher: AnyPublisher<Int, Never>
→ “정수를 계속 emit(방출)할 수 있지만, 실패(Failure)는 절대 발생하지 않는다”
Never는 Combine에서 “에러가 발생하지 않는 타입” 을 뜻하는 특별한 타입이에요.
즉, Error의 반대 역할이라고 생각하면 돼요.
🧩 그래서 AnyPublisher<[EmotionDiaryModel], Never>는 이렇게 해석돼요:
| 요소 | 의미 |
| [EmotionDiaryModel] | 일기 데이터 배열을 내보냄 |
| Never | 발행 중 에러 발생 가능성 없음 |
| AnyPublisher | 내부가 어떤 구체적인 Publisher인지 숨김 |
즉,
"이건 Combine 스트림이지만, 세부 구현은 몰라도 되고
구독만 하면 [EmotionDiaryModel]을 계속 받을 수 있어요"
라는 뜻이에요 ✅
🧩 2️⃣ diariesSubject.eraseToAnyPublisher() 의 이유
diariesSubject는 실제로 이렇게 선언돼 있었죠 👇
private let diariesSubject = CurrentValueSubject<[EmotionDiaryModel], Never>([])
즉, 실제 타입은 CurrentValueSubject<[EmotionDiaryModel], Never>예요.
근데 이 타입을 직접 외부에 노출하면 안 돼요.
⚠️ 왜냐하면?
CurrentValueSubject는 send() 메서드를 갖고 있어서
외부에서도 값을 강제로 바꿀 수 있기 때문이에요.
store.diariesSubject.send([]) // 😱 외부에서 데이터 변경 가능
이러면 ViewModel이 데이터 흐름을 통제할 수 없게 돼요.
→ 즉, SSOT(Single Source of Truth, 단일 데이터 소스) 원칙이 깨져요.
💡 그래서 .eraseToAnyPublisher() 를 쓰는 이유는
내부의 구체 타입(CurrentValueSubject)을 감추고,
“읽기 전용”의 추상 타입(AnyPublisher)으로 변환하는 거예요.
var diariesPublisher: AnyPublisher<[EmotionDiaryModel], Never> {
diariesSubject.eraseToAnyPublisher()
}
이렇게 하면 외부에서는 이제 send() 같은 걸 쓸 수 없어요.
오직 sink(구독)만 가능해져요 👇
store.diariesPublisher
.sink { diaries in
print("일기 업데이트:", diaries)
}
.store(in: &cancellables)
⚖️ 정리하면
| 구문 | 역할 | 비유 |
| diariesSubject | 내부 데이터 소스 (실제 값 저장소) | “물탱크” |
| eraseToAnyPublisher() | 외부로 노출할 때 보호막 역할 | “수도관” |
| AnyPublisher<[EmotionDiaryModel], Never> | 외부에서 볼 수 있는 읽기 전용 Publisher | “수돗물만 받을 수 있음 (밸브는 잠겨 있음)” |
✅ 최종 한 줄 요약
eraseToAnyPublisher()는 내부의 CurrentValueSubject를
외부에서 수정 못하게 숨기고,
AnyPublisher는 “이건 데이터를 방출만 하는 읽기 전용 스트림”이라는 계약을 뜻한다.
'감정일기(가칭)' 카테고리의 다른 글
| 🧩 Swift 6에서 @MainActor와 Singleton(.shared) 접근 시 발생하는 오류 해결하기 (0) | 2025.10.24 |
|---|---|
| 🍋 DiaryStore 이후의 ViewModel 설계 — 화면 단위로 나누는 이유와 구조 (0) | 2025.10.24 |
| 🧪 Xcode에서 XCTestCase로 단위 테스트 작성하기— DiaryStore 테스트를 예시로 배우는 실전 가이드 (0) | 2025.10.23 |
| 🧭 DiaryProviding 프로토콜 — 읽기 전용 인터페이스로 ViewModel을 보호하기 (0) | 2025.10.23 |
| 🍋 DiaryStore 설계 총정리 — “하나의 진실(Single Source of Truth)” 패턴으로 Core Data 관리하기 (0) | 2025.10.23 |