programming/Swift

[Swift/iOS] CoreData 사용하기(3) - 데이터 저장하기, 데이터 불러오기 기초

마들브라더 2023. 5. 6. 01:00

https://modelinspring.tistory.com/91

 

[Swift/iOS] CoreData 사용하기(2) - CoreData Stack 설정하기 From 공식문서

! 공식문서를 참고한 글입니다.https://developer.apple.com/documentation/coredata/setting_up_a_core_data_stack https://modelinspring.tistory.com/90 [Swift/iOS] CoreData 사용하기(1) - 프로젝트 중간에 추가하기, Entity 만들기Core

modelinspring.tistory.com

위 포스트에 이은 CoreData 세 번째 포스트입니다.

 

Core Data 데이터 저장하기

이전 포스트에서 Car Entity를 만들어놓았습니다.

이제 데이터를 저장해보겠습니다.

    let myCar: [String: Any] = ["brand": "KIA", "color": "black", "price": 3000]

뷰 컨트롤러에서 다음과 같이 딕셔너리 형태로 저장할 값을 만들었습니다.

 

이전 포스팅에서 context는 인스턴스들의 변화를 추적한다고 했습니다.

일종의 메서드라고 생각하면 편할 것 같습니다.

저장하는 메서드를 사용하기 위해서 context를 사용해야 하고,

context 역시 다른 인스턴스들과 함께 container에 포함되어 있습니다.

 

현재 persistent container는 AppDelegate에 있습니다.

 

AppDelegate의 persistent containser에서 context를 불러오기

// AppDelegate 불러오기
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
// AppDelegate 안에 있는 persistentContainer에서 context 가져오기
let context = appDelegate.persistentContainer.viewContext

 

context를 가져왔습니다.

저장하려는 데이터의 entity도 가져와야 합니다.

entity는 데이터 모델 내에서 데이터 유형을 나타낸다고 했습니다.

우리가 저장할 데이터의 유형을 entity와 맞춰야 합니다.

 

Entity 불러오기

guard let entity = NSEntityDescription.entity(forEntityName: "Car", in: context) else { return }

"Car" 이름의 entity를 불러왔습니다.

 

Object 만들기

Object는 무엇일까요?

Core Data에서 Object란 모델 객체(Entity)의 인스턴스입니다.

클래스를 만들고 클래스의 인스턴스를 만드는 것처럼, Entity로 Object를 만든다고 하면 이해가 쉬울 것 같습니다.

let car = NSManagedObject(entity: entity, insertInto: context)

 

object를 만들었고, 이제 object에 값도 넣어야 합니다.

car.setValue(myCar["brand"], forKey: "brand")
car.setValue(myCar["color"], forKey: "color")
car.setValue(myCar["price"], forKey: "price")

 

저장하고자 하는 Object가 준비되었습니다.
context를 통해 저장하는 방법으로 넘어가겠습니다.

 

Context를 통해 저장하기

try? context.save()

 

한줄의 코드로 저장을 할 수 있습니다.
전체 코드를 보면 아래와 같습니다.

override func viewDidLoad() {
    super.viewDidLoad()

    guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
    let context = appDelegate.persistentContainer.viewContext

    guard let entity = NSEntityDescription.entity(forEntityName: "Car", in: context) else { return }

    let car = NSManagedObject(entity: entity, insertInto: context)
    car.setValue(myCar["brand"], forKey: "brand")
    car.setValue(myCar["color"], forKey: "color")
    car.setValue(myCar["price"], forKey: "price")

    try? context.save()
}

 

데이터 불러오기

Entity 전체의 값을 불러오는 것도 아래와 같은 코드 한 줄로 실행할 수 있습니다.

let newcar = try? context.fetch(Car.fetchRequest())
print(type(of: newcar)) // Optional<Array<Car>>
print(newcar)

 

 

기본적인 저장과 불러오기 성공!

 

그런데, 저장하는 코드를 다 주석 처리한 후,

불러오는 코드만 둔 채 다시 run 하면 불러온 data의 값들이 다 fault로 나오는 걸 볼 수 있습니다.

 

불러오기 코드를 다음과 같이 수정해보겠습니다.

let request = Car.fetchRequest()
request.returnsObjectsAsFaults = false
let newcar = try? context.fetch(request)
print(newcar)

해결!

Fault는 메모리에 완전히 올라오지 않은 object를 나타내는 placeHolder라고 합니다.
(faulting이라는 기술을 사용해서 메모리 사용 최소화)

returnsObjectsAsFaults 값이 true인 경우, NSFetchRequest를 사용해서 가져온 객체를 fault로 반환합니다.

기본값은 true인데, Core Data는 Object를 가져와서 row cache를 정보로 채우고, managed object를 faults로 반환합니다.

 

실제 값을 사용할 때에는 메모리에 올라오기 때문에 fault로 보이지 않습니다.

guard let newcar = try? context.fetch(Car.fetchRequest()) else { return }
newcar.forEach {
    print($0.brand, $0.color, $0.price)
}

해결!

 

참고 

https://zeddios.tistory.com/987

https://velog.io/@ssionii/Core-Data%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%84%EB%9D%BC%EB%B3%B4%EC%9E%90-3-Fetch-Data
https://developer.apple.com/documentation/coredata/nsfetchrequest/1506756-returnsobjectsasfaults