앱을 처음 만들 때는 데이터가 얼마 없기 때문에
“그냥 한 번에 다 불러오면 되지 않나?” 싶을 수 있습니다.
하지만 사용자가 데이터를 꾸준히 쌓기 시작하면,
이 단순한 접근이 성능 저하의 주범이 되죠.
이번 글에서는 내가 개발 중인 감정일기 앱을 예로 들어,
데이터 양과 화면의 성격에 따라
어떻게 “로딩 전략”을 구분할 수 있는지 정리해보려 합니다.
🎯 상황 요약
1. 앱은 Core Data + FileManager 기반으로 구성되어 있습니다.
2. 감정일기 1개에는 최대 8장의 이미지가 첨부될 수 있습니다.
3. 데이터는 점점 늘어날 수 있으므로, 효율적인 로딩 전략이 필요합니다.
🚀 1️⃣ 데이터 로딩 전략의 핵심 개념
앱에서 데이터를 읽는 방법은 크게 두 가지가 있습니다.
| 방식 | 설명 | 장점 | 단점 |
| 동기 로딩 (Synchronous) |
한 번에 모든 데이터를 불러와서 즉시 표시 | 간단하고 빠른 구현 | 데이터가 많아질수록 성능 저하 |
| 점진적 로딩 (Pagination) |
데이터를 일정 단위로 나누어(fetchLimit) 순차적으로 불러옴 | 성능, UX 우수 | 구현 복잡도 증가 |
⚙️ 2️⃣ Pagination(페이징)이란?
📖 페이징은 데이터를 “한 번에 전부” 불러오는 대신,
필요한 만큼만 나누어 점진적으로(fetchLimit / fetchOffset) 불러오는 기술입니다.
예를 들어,
한 화면에 최대 10개의 일기를 보여주고,
Core Data에서는 한 번에 20개만 fetch 한 뒤,
사용자가 스크롤하면 다음 20개를 “미리(prefetch)” 로드하는 식입니다.
이 방식의 장점은 명확합니다.
UI가 끊기지 않고, 앱이 부드럽게 작동합니다.
func fetchDiaries(limit: Int? = nil, offset: Int = 0) -> [EmotionDiaryEntity] {
let request: NSFetchRequest<EmotionDiaryEntity> = EmotionDiaryEntity.fetchRequest()
request.sortDescriptors = [NSSortDescriptor(key: "createdAt", ascending: false)]
if let limit = limit {
request.fetchLimit = limit
request.fetchOffset = offset
}
return (try? context.fetch(request)) ?? []
}
이렇게 해두면,
초기에는 전체 fetch로 단순하게 쓰고,
데이터가 많아졌을 때는 limit / offset만 지정해
자연스럽게 페이징으로 전환할 수 있습니다 ✅
🧠 3️⃣ 앱의 성장 단계별 로딩 전략
🏠 (1) 홈 화면 — “최근 리스트” 섹션
데이터 양이 적고, 정해진 개수만 표시
예: “최근 감정일기 5개”, “오늘의 일기 1개”
Core Data fetch 시 fetchLimit = 5만 주면 충분
페이징은 불필요 (오히려 코드만 복잡해짐)
func fetchRecentDiaries(limit: Int = 5) -> [EmotionDiaryEntity] {
let request: NSFetchRequest<EmotionDiaryEntity> = EmotionDiaryEntity.fetchRequest()
request.sortDescriptors = [NSSortDescriptor(key: "createdAt", ascending: false)]
request.fetchLimit = limit
return (try? context.fetch(request)) ?? []
}
💡 핵심 요약:
홈 화면은 “고정 개수만 즉시 로드”가 가장 효율적입니다.
📓 (2) 감정일기 목록 화면
초반엔 동기로 충분하지만, 데이터가 쌓이면 점진적 로딩으로 확장
앱 초기에 사용자가 작성한 일기는 많아봐야 10개 미만입니다.
이때는 전체 fetch로 충분히 빠르고, 유지보수도 간단합니다.
하지만 데이터가 50개, 100개 이상으로 늘어나면
이미지 로드만으로도 UI가 끊기기 시작하죠.
그럴 때 점진적 로드(Pagination) 로 전환합니다.
한 번에 20개만 가져오기 (fetchLimit = 20)
사용자가 스크롤할 때마다 다음 20개 prefetch
필요 시 async/await을 활용해 백그라운드에서 이미지 로드
extension DiaryListViewController: UICollectionViewDataSourcePrefetching {
func collectionView(_ collectionView: UICollectionView, prefetchItemsAt indexPaths: [IndexPath]) {
let threshold = diaryList.count - 5
if indexPaths.contains(where: { $0.item > threshold }) {
loadNextBatch() // 다음 데이터 미리 로드
}
}
}
📌 핵심 요약:
감정일기 화면은 초반엔 단순하게,
데이터가 많아질 경우 페이징으로 전환할 수 있도록 구조를 열어둡니다.
🖼️ (3) 사진으로 검색 화면
이미지 단위 데이터 → 데이터가 많으므로 페이징 필수
사진은 감정일기보다 훨씬 많이 쌓입니다.
일기 1개에 8장, 10개의 일기만 써도 80장의 이미지가 되니까요.
이런 화면은 처음부터 Pagination 기반으로 설계해야 합니다.
func fetchImages(limit: Int, offset: Int) -> [DiaryImageEntity] {
let request: NSFetchRequest<DiaryImageEntity> = DiaryImageEntity.fetchRequest()
request.sortDescriptors = [NSSortDescriptor(key: "id", ascending: false)]
request.fetchLimit = limit
request.fetchOffset = offset
return (try? context.fetch(request)) ?? []
}
- 스크롤 시점마다 prefetch
- 이미지 로딩은 비동기 처리로 부드럽게 표시
- 메모리 효율 + UX 모두 향상
📸 핵심 요약:
“사진으로 검색” 같은 탐색 중심 화면은
처음부터 점진적 로딩으로 가는 것이 맞습니다.
🧩 4️⃣ 전체 구조 요약
| 화면 | 로딩 방식 | 설명 |
| 🏠 홈(최근 리스트) | 동기 | 항상 적은 데이터만 표시 |
| 📓 감정일기 목록 | 초반엔 동기 → 나중엔 페이징 | 데이터가 많아질 때 대비 |
| 🖼️ 사진으로 검색 | 항상 페이징 | 이미지 중심 대량 데이터 |
🧭 5️⃣ 추천 설계 패턴
enum FetchMode {
case all
case paged(limit: Int, offset: Int)
}
func fetchDiaries(mode: FetchMode) -> [EmotionDiaryEntity] {
let request: NSFetchRequest<EmotionDiaryEntity> = EmotionDiaryEntity.fetchRequest()
request.sortDescriptors = [NSSortDescriptor(key: "createdAt", ascending: false)]
switch mode {
case .all:
break
case .paged(let limit, let offset):
request.fetchLimit = limit
request.fetchOffset = offset
}
return (try? context.fetch(request)) ?? []
}
이렇게 만들어두면
처음엔 .all로 전체 로딩을 사용하다가,
데이터가 많아지면 .paged(limit: 20, offset: 0)로 바로 전환할 수 있습니다.
즉, 한 번의 설계로 두 상황을 모두 커버할 수 있죠 💪
✨ 마무리 — 앱은 “점진적 성숙”을 고려해서 설계하자
앱의 초반엔 “단순함”이 효율이고,
데이터가 쌓이면 “확장성”이 생명입니다.
초반엔 동기 로딩으로 단순하게 시작하고,
데이터가 늘어나면 페이징 구조로 확장,
이미지 중심 탐색 화면은 처음부터 페이징 기반으로 설계.
이렇게 단계별로 로딩 전략을 세워두면
앱이 성장하더라도 구조를 뜯어고칠 일이 없어요.
💬 즉, 감정일기 앱은 ‘데이터의 양과 성격’에 따라 로딩 전략을 다르게 가져가는 것이 핵심입니다.
작을 땐 단순하게, 커지면 점진적으로.
이것이 “지속 가능한 iOS 아키텍처 설계”의 첫걸음이에요 🌱
'감정일기(가칭)' 카테고리의 다른 글
| ☁️ Core Data에서 Firebase로 확장하는 iOS 데이터 구조 설계 (0) | 2025.10.18 |
|---|---|
| 🧩 Core Data 매니저 네이밍, 어떻게 하는 게 좋을까? (0) | 2025.10.18 |
| 🚀 현실적인 iOS 데이터 로딩 전략 — Core Data와 Pagination(페이징) 이야기 (0) | 2025.10.17 |
| 🪵 개발/배포 환경을 구분한 로깅 설계 (0) | 2025.10.17 |
| 📦 Core Data와 FileManager로 이미지 관리 구조 설계하기 (0) | 2025.10.17 |