728x90
SMALL
✨ 목표
이번 글에서는 가계부 앱에서 Core Data로 저장된 지출 내역을 전체 조회하거나 특정 ID로 조회하는 방법과, Core Data Entity(ExpenseEntity)를 우리가 ViewModel/화면에서 사용하기 위한 데이터 모델(ExpenseModel)로 변환하는 방법을 함께 정리합니다.
✅ 전체 흐름 요약
| 역할 | 함수 이름 | 설명 |
| CoreData → Model 변환 | toModel() | Entity 데이터를 앱에서 사용할 수 있는 형태로 변환 |
| 전체 데이터 읽기 | readAllTransaction() | 모든 지출 내역을 최신순으로 읽기 |
| 특정 데이터 읽기 | readTransactionByID(by:) | 특정 ID 기반으로 하나의 내역 읽기 |
1️⃣ ExpenseEntity → ExpenseModel 변환: toModel()
extension ExpenseEntity {
func toModel() -> ExpenseModel? {
guard
let idString = self.id,
let uuid = UUID(uuidString: idString),
let transactionRaw = self.transaction,
let transaction = TransactionType(rawValue: transactionRaw),
let category = self.category,
let date = self.date,
let memo = self.memo
else {
print("❌ toModel 변환 실패: 필수 값 누락")
return nil
}
let image: UIImage?
if let path = self.imagePath, !path.isEmpty {
image = TransactionFileManager.shared.loadImage(from: path)
} else {
image = nil
}
return ExpenseModel(
id: uuid,
transaction: transaction,
category: category,
amount: Int(self.amount),
image: image,
date: date,
memo: memo
)
}
}
🧩 어떤 역할을 하나요?
- Core Data는 NSManagedObject 기반의 ExpenseEntity 객체를 사용하지만, 앱의 UI나 ViewModel에서는 ExpenseModel이라는 더 가볍고 타입 안정성 있는 모델을 사용하길 원해요.
- 이 함수는 Entity → Model 변환을 담당합니다.
- 문자열 기반으로 저장된 UUID, Enum, 이미지 경로 등을 올바른 타입으로 매핑해줘요.
📝 주요 포인트
- UUID, TransactionType, UIImage 등 타입 안전하게 변환
- 이미지 경로가 있으면 TransactionFileManager로 이미지 불러오기
- nil 체크 꼼꼼히 → 실패 시 nil 반환으로 안정성 확보
2️⃣ 전체 지출 데이터 불러오기: readAllTransaction()
func readAllTransaction() -> AnyPublisher<[ExpenseModel], Error> {
return Future { [weak self] promise in
guard let self = self else {
print("❌ TransactionManager: self가 nil이므로 종료")
return
}
let fetchRequest: NSFetchRequest<ExpenseEntity> = ExpenseEntity.fetchRequest()
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "date", ascending: false)]
do {
let expenseEntities = try self.context.fetch(fetchRequest)
print("✅ Read 성공, 총 \(expenseEntities.count)개 불러옴")
let transactions = expenseEntities.compactMap { $0.toModel() }
promise(.success(transactions))
} catch {
print("❌ 불러오기 실패: \(error.localizedDescription)")
promise(.failure(error))
}
}
.eraseToAnyPublisher()
}
💡 흐름 설명
- fetchRequest를 만들어 모든 ExpenseEntity 데이터를 요청
- sortDescriptors로 최신순 정렬
- context.fetch()로 Core Data에서 불러오기
- compactMap { $0.toModel() }로 ExpenseModel 리스트로 변환
- Combine의 Future로 비동기 반환
💎 장점
- 최신순 정렬로 UI에 바로 사용 가능
- Entity → Model 변환 덕분에 ViewModel에 바로 전달 가능
- Combine 구조로 구독해서 UI 자동 업데이트 가능
3️⃣ 특정 지출 ID로 불러오기: readTransactionByID(by:)
func readTransactionByID(by id: UUID) -> AnyPublisher<ExpenseModel?, Error> {
return Future { [weak self] promise in
guard let self = self else {
print("❌ TransactionManager: self가 nil이므로 종료")
return
}
let fetchRequest: NSFetchRequest<ExpenseEntity> = ExpenseEntity.fetchRequest()
fetchRequest.predicate = NSPredicate(format: "id == %@", id.uuidString)
fetchRequest.fetchLimit = 1
do {
let result = try self.context.fetch(fetchRequest)
let model = result.first?.toModel()
if model == nil {
print("⚠️ 해당 ID로 찾은 데이터 없음")
} else {
print("✅ \(id) 읽기 성공")
}
promise(.success(model))
} catch {
print("❌ ID로 불러오기 실패: \(error.localizedDescription)")
promise(.failure(error))
}
}
.eraseToAnyPublisher()
}
💡 흐름 설명
- fetchRequest에 NSPredicate로 필터 조건 설정 (id == UUID)
- fetchLimit = 1로 하나만 가져오게 제한
- 결과를 toModel()로 변환 후 반환
💎 장점
- 상세 보기, 수정, 삭제 등 ID 기반 액션에서 사용
- Core Data의 고유 식별자를 활용하므로 데이터 무결성 보장
🎯 왜 이 방식이 좋은가?
| 항목 | 이유 |
| MVVM + Combine | 비동기 구조, 구독 구조로 UI 연동에 유리 |
| toModel 사용 | Entity와 Model 분리로 유지보수성 향상 |
| 확장성 확보 | 카테고리별, 기간별 검색도 쉽게 확장 가능 |
[함께 보면 좋은 글]
https://explorer89.tistory.com/443
💾 Core Data와 FileManager로 지출 내역 저장하기
Core Data + FileManager + Combine 조합으로 데이터와 이미지까지 한 번에 저장하기✨ 목표지출 내역을 저장할 때,기본 정보(날짜, 금액, 메모 등)는 Core Data에선택 이미지가 있다면 FileManager에 저장하고
explorer89.tistory.com
728x90
LIST
'Project > ReceiptMind' 카테고리의 다른 글
| 📦 iOS MVVM 가계부 앱 - Core Data 삭제(Delete) + 이미지 제거까지 정리 (1) | 2025.08.02 |
|---|---|
| 📚 iOS MVVM 가계부 앱 - Core Data 수정(Update) + 이미지까지 깔끔히 반영하는 법 (1) | 2025.08.02 |
| 💾 Core Data와 FileManager로 지출 내역 저장하기 (2) | 2025.08.01 |
| 📦 Swift에서 FileManager로 이미지 저장하기 – 이미지 저장, 경로 관리, 불러오기까지의 전체 흐름 정리 (1) | 2025.07.31 |
| 📱 iOS 가계부 앱 데이터 모델 설계하기 (3) | 2025.07.30 |