개발/Swift
[Swift] CoreData 사용해보기: CRUD 구현 가이드
덤벨로퍼
2024. 5. 18. 13:50
문제
- API 네트워킹시 네트워크 문제가 있을경우 내부저장 데이터를 리턴해주는 로직 필요.
- CoreData는 내부데이터 이므로 Repository 에서 접근 하는게 맞다고 판단 했다.
근데 CoreData는 Appdelegate의 persistentContainer.viewContext 에 접근 해야함
Repository -> CoreData -> Appdelegate
이는 클린 아키텍쳐 구성상 의존성의 방향이 잘못되었다 생각
해결
- CoreData 를 사용해서 데이터를 저장 & 사용
- Repository 생성시 viewContext를 주입받아 사용
Coordinator 패턴이나 의존성 주입 하는 부분에서 해주면 좋을것 같다.
let appDelegate = UIApplication.shared.delegate as? AppDelegate
let viewContext = appDelegate?.persistentContainer.viewContext
let repository = NewsRepository(viewContext: viewContext, network: NewsNetwork())
let viewModel = ViewModel(repository: repository)
let viewController = ViewController(viewModel: viewModel)
let rootVC = UINavigationController(rootViewController: viewController)
구현
- CoreData Entity 설정은 이미 해둠
삭제
private func deleteAllNewsCoreData() {
let fetchRequestResult: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "NewsItem")
let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequestResult)
do {
try viewContext?.execute(deleteRequest)
try viewContext?.save()
} catch let error {
print("deleteAllNewsCoreData Error - \\(error)")
}
}
NewsItem 엔티티 저장된 리스트 모두 지워버림
저장
private func saveNewsCoreData(news: [News]) {
guard let viewContext = viewContext,
let entity = NSEntityDescription.entity(forEntityName: "NewsItem", in: viewContext) else { return }
news.forEach { newsItem in
let newsObject = NSManagedObject(entity: entity, insertInto: viewContext)
newsObject.setValue(newsItem.publishedAt, forKey: "publishedAt")
newsObject.setValue(newsItem.title, forKey: "title")
newsObject.setValue(newsItem.urlToImage, forKey: "urlToImage")
newsObject.setValue(newsItem.url, forKey: "url")
}
do {
try viewContext.save()
} catch let error {
print("saveNewsCoreData Error - \\(error)")
}
}
객체의 데이터를 모두 꺼내서 Coredata 엔티티 생성 후 (반복) 저장
읽기
private func readNewsCoreData() -> [News] {
let fetchRequest: NSFetchRequest<NewsItem> = NewsItem.fetchRequest()
do {
guard let result = try viewContext?.fetch(fetchRequest) else { return [] }
let news: [News] = result.compactMap { news in
guard let title = news.value(forKey: "title") as? String,
let url = news.value(forKey: "url") as? String else { return nil }
let publishedAt = news.value(forKey: "publishedAt") as? Date
let urlToImage = news.value(forKey: "urlToImage") as? String
return News(title: title, url: url, urlToImage: urlToImage, publishedAt: publishedAt)
}
return news
} catch let error {
print("readNewsCoreData Error - \\(error)")
return []
}
}
Coredata 엔티티 (리스트) 꺼내와서 객체 생성후 리턴