CoreData로 어떤 속성을 저장해야 앱을 다시 켰을 때, 사용자가 저장된 위치에 해당하는 날씨를 제공할 수 있을지 고민해보았다.
1. 사용자가 검색창에 자신이 원하는 지역을 검색한다.
2. 원하는 지역의 날씨 정보창에서 추가하기를 눌러 지역의 데이터를 저장한다.
3. 지역의 데이터만 CoreData에 저장해놓고 앱이 다시 실행될 때 지역의 데이터를 불러온다.
4. API 통신을 통해 불러와진 지역의 데이터를 통해 그 지역의 날씨를 확인할 수 있게 만들어준다.
그렇다면 지역의 데이터를 저장하는 방법은 크게 두가지 방식으로 나뉠 수 있다.
첫 번째 방법은 zip code를 저장해서 불러내는 것이였다. 해당 지역에 속하는 zip code를 CoreData에 저장해놓고 불러오는 방식이다.
두 번째 방법은 위도와 경도를 저장해서 불러내는 것이었다. 위와 같은 방식이지만, 저장해야할 속성 값이 두개이며, 데이터 관리가 좀 더 복잡해진다.
우선, OneWeatherMap에서 지역의 데이터를 뽑아내는 방식은 위도와 경도이다. 그래서 선택의 여지 없이 위도와 경도로 구성해야했다.
Entity 이름은 MapData, Attribute에서 위도와 경도는 각각 lat lon 으로 구성했으며 Double 타입으로 구성하여 소수점까지 저장될 수 있도록 구성했다.
Entity Inspector 에서 Codegen을 Class Definition으로 설정해놓으면, 따로 swift파일에서 class를 설정하지 않아도 자동으로 설정이 되있다.
이제 나는 MapData라는 Class에 lat 과 lon 이라는 변수가 들어있는 것이다.
날씨앱에서 자신이 지역을 추가하고 읽어서 다시 보여주고 지워주는 기능은 필요하지만, 자신이 설정한 지역을 수정하는 부분은 구현하지 않아도 된다고 반단했다. 그래서 CRUD에서 U를 뺀 CRD만 구성하게 되었다.
import Foundation
import CoreData
import UIKit
class CoreDataManager {
// 싱글톤 패턴 적용
static var shared = CoreDataManager()
private let persistentContainer: NSPersistentContainer
private init() {
persistentContainer = NSPersistentContainer(name: "Thefirstorecast")
persistentContainer.loadPersistentStores { (_, error) in
if let error = error {
fatalError("Failed to lad persistent storess: \(error)")
}
}
}
우선 싱글톤 패턴을 적용하여 UI에서 관리하기 편하게 만들어 봤다.
// Mapdata 생성하는 메서드
func createMapData(lat: Double, lon: Double) {
let context = persistentContainer.viewContext
let mapData = MapData(context: context)
mapData.lat = lat
mapData.lon = lon
do {
try context.save()
print("맵 데이터 생성이 성공적으로 진행")
} catch {
context.rollback()
print("맵 데이터 생성 실패: \(error.localizedDescription)")
}
}
// MapData 읽는 메서드
func readMapData() -> [NSManagedObject] {
let context = persistentContainer.viewContext
let fetchRequest: NSFetchRequest<MapData> = MapData.fetchRequest()
do {
let mapData = try context.fetch(fetchRequest)
return mapData
} catch {
print("맵 데이터 로드 실패: \(error.localizedDescription)")
return []
}
}
// MapData 삭제 메서드
func deleteMapData(at indexPath: IndexPath) {
let context = persistentContainer.viewContext
let mapData = readMapData()
let dataToDelete = mapData[indexPath.row]
context.delete(dataToDelete)
do {
try context.save()
print("맵 데이터 삭제 성공")
} catch {
context.rollback()
print("맵 데이터 삭제 실패: \(error.localizedDescription)")
}
}
}
기초적인 틀은 다 잡은 것 같고 가장 중요한 것은 API와의 연결, UI와 잘 녹이는 게 가장 큰 핵심인 것 같다.