-
CoreData와 실습(2)카테고리 없음 2024. 7. 10. 16:42
CoreData 를 활용한 CRUD(Create, Read, Update, Delete)
이전에 NSPersistentConatiner 를 만들었으므로, ViewController 에서 이를 활용해서 데이터 접근
CoreData와 실습(1)
CoreData 는 앱에서 기기의 **디스크**에 데이터를 읽고 쓸 수 있게 돕는 프레임워크 Swift 로 기기 내 디스크에 데이터를 저장할 수 있는 대표적인 방법으로는CoreDataUserDefaults 1. CoreData 프로젝트 생
bluewiper.tistory.com
1. CoreData 를 통해 CRUD 의 C, R 을 하는 과정
- ViewController.swift
- entityName, forKey를 위해 "PhoneBook", "name", "phoneNumber"처럼 일일이 String값을 입력해서 호출한다.
- 일일이 String값을 입력해주는 일을 줄이기 위해 이후에 리팩토링을 하게 된다.
import UIKit import CoreData class ViewController: UIViewController { //ViewController의 프로퍼티인 container가 Appdelegate에 있는 persistentConatiner를 참조하게 되는 과정 var container: NSPersistentContainer! override func viewDidLoad() { super.viewDidLoad() let appDelegate = UIApplication.shared.delegate as! AppDelegate self.container = appDelegate.persistentContainer createData(name: "Jean", phoneNumber: "010-1111-2222") readAllDate() } //CoreDataPractice에 데이터 CRUD 중 Create를 하는 과정 *Entity 형태를 지켜서 삽입 func createData(name: String, phoneNumber: String) { guard let entity = NSEntityDescription.entity(forEntityName: "PhoneBook", in: self.container.viewContext) else { return } //새롭게 저장할 PhoneBook entity 객체 생성 let newPhoneBook = NSManagedObject(entity: entity, insertInto: self.container.viewContext) //newPhoneBook의 Attribute(속성) 지정 newPhoneBook.setValue(name, forKey: "name") newPhoneBook.setValue(phoneNumber, forKey: "phoneNumber") //데이터에 변조(CoreDate에 데이터 생성)가 일어났으므로 Appdelegate의 saveContext 메서드를 사용해야한다. do { try self.container.viewContext.save() print("문맥 저장 성공") } catch { print("문맥 저장 실패") } } //CoreDataPractice에서 데이터 CRUD 중 Read를 하는 과정 func readAllDate() { do { let phoneBooks = try self.container.viewContext.fetch(PhoneBook.fetchRequest()) for phoneBook in phoneBooks as [NSManagedObject] { if let name = phoneBook.value(forKey: "name") as? String, let phoneNumber = phoneBook.value(forKey: "phoneNumber") as? String { print("name:\(name), phoneNumber: \(phoneNumber)") } } } catch { print("데이터 읽기 실패") } } }
디스크에 저장했으므로, 데이터를 저장한 코드를 삭제한 뒤 앱을 다시켜도 데이터가 남아있음을 확인 가능
리팩토링 전 PhoneBook+CoreDataClass.swift
import Foundation import CoreData @objc(PhoneBook) public class PhoneBook: NSManagedObject { }
리팩토링 후 PhoneBook+CoreDataClass.swift
import Foundation import CoreData @objc(PhoneBook) public class PhoneBook: NSManagedObject { public static let className = "PhoneBook" public enum Key { static let name = "name" static let phoneNumber = "phoneNumber" } }
→ static 프로퍼티는 그 타입에 대고 호출을 할 수 있는 프로퍼티이다.
→ PhoneBook.className → PhoneBook 이라는 클래스 타입에 대고 점을찍고 호출
왜 하는 것일까?
1. 자동완성 기능을 사용할 수 있다.
2. 직접 String 값인 "phoneNumber"라고 치지 않아도 되니 오타와 같은 휴먼에러를 줄인다.
3. 값을 수정할 일이 생길 때 일일이 찾아가지 않아도 PhoneBook+CoreDataClass.swift 한 곳에서 수정할 수 있다.
4. 성격이 같은 프로퍼티끼리 모아서 관리할 수 있다.
리팩토링 후 ViewController.swift
import UIKit import CoreData class ViewController: UIViewController { //ViewController의 프로퍼티인 container가 Appdelegate에 있는 persistentConatiner를 참조하게 되는 과정 var container: NSPersistentContainer! override func viewDidLoad() { super.viewDidLoad() let appDelegate = UIApplication.shared.delegate as! AppDelegate self.container = appDelegate.persistentContainer createData(name: "Jean", phoneNumber: "010-1111-2222") readAllDate() } //CoreDataPractice에 데이터 CRUD 중 Create를 하는 과정 *Entity 형태를 지켜서 삽입 func createData(name: String, phoneNumber: String) { guard let entity = NSEntityDescription.entity(forEntityName: PhoneBook.className, in: self.container.viewContext) else { return } //새롭게 저장할 PhoneBook entity 객체 생성 let newPhoneBook = NSManagedObject(entity: entity, insertInto: self.container.viewContext) //newPhoneBook의 Attribute(속성) 지정 newPhoneBook.setValue(name, forKey: PhoneBook.Key.name) newPhoneBook.setValue(phoneNumber, forKey: PhoneBook.Key.phoneNumber) //데이터에 변조(CoreDate에 데이터 생성)가 일어났으므로 Appdelegate의 saveContext 메서드를 사용해야한다. do { try self.container.viewContext.save() print("문맥 저장 성공") } catch { print("문맥 저장 실패") } } //CoreDataPractice에서 데이터 CRUD 중 Read를 하는 과정 func readAllDate() { do { let phoneBooks = try self.container.viewContext.fetch(PhoneBook.fetchRequest()) for phoneBook in phoneBooks as [NSManagedObject] { if let name = phoneBook.value(forKey: PhoneBook.Key.name) as? String, let phoneNumber = phoneBook.value(forKey: PhoneBook.Key.phoneNumber) as? String { print("name:\(name), phoneNumber: \(phoneNumber)") } } } catch { print("데이터 읽기 실패") } } }
EntityName, forKey를 위해 이전처럼 String값이 아닌 클래스를 호출한다.
Back to CRUD
2. CoreData 를 통해 CRUD 의 U 하는 과정
//CoreDataPractice에서 데이터 CRUD 중 name에 대해 Update를 하는 과정 func updateData(currentName: String, updateName: String) { //업데이트를 위해 데이터를 찾는 과정 let fetchRequest = PhoneBook.fetchRequest() fetchRequest.predicate = NSPredicate(format: "name == %@", currentName) do { let result = try self.container.viewContext.fetch(fetchRequest) for data in result as [NSManagedObject] { // data 중 name을 updateName으로 update 한다. data.setValue(updateName, forKey: PhoneBook.Key.name) } // 데이터 변조가 일어났으므로 save해준다. try self.container.viewContext.save() print("데이터 수정 성공") } catch { print("데이터 수정 실패") } }
3. CoreData 를 통해 CRUD 의 D 를 하는 과정
//CoreDataPractice에서 데이터 CRUD 중 Delete를 하는 과정 * name으로 데이터를 추적해서 삭제한다. func deleteData(name: String) { //삭제를 위해 데이터를 찾는 과정 let fetchRequest = PhoneBook.fetchRequest() fetchRequest.predicate = NSPredicate(format: "name == %@", name) do { let result = try self.container.viewContext.fetch(fetchRequest) for data in result as [NSManagedObject] { self.container.viewContext.delete(data) } // 데이터 변조가 일어났으므로 save해준다. try self.container.viewContext.save() print("데이터 삭제 성공") } catch { print("데이터 삭제 실패") } }
CRUD별 호출 모습
1. Create와 Read
import UIKit import CoreData class ViewController: UIViewController { //ViewController의 프로퍼티인 container가 Appdelegate에 있는 persistentConatiner를 참조하게 되는 과정 var container: NSPersistentContainer! override func viewDidLoad() { super.viewDidLoad() let appDelegate = UIApplication.shared.delegate as! AppDelegate self.container = appDelegate.persistentContainer createData(name: "Jean", phoneNumber: "010-1111-2222") readAllData() }
2. Update
import UIKit import CoreData class ViewController: UIViewController { //ViewController의 프로퍼티인 container가 Appdelegate에 있는 persistentConatiner를 참조하게 되는 과정 var container: NSPersistentContainer! override func viewDidLoad() { super.viewDidLoad() let appDelegate = UIApplication.shared.delegate as! AppDelegate self.container = appDelegate.persistentContainer createData(name: "Jean", phoneNumber: "010-1111-2222") updateData(currentName: "Jean", updateName: "Yejin") // 아래에서 updateData라는 func를 만든 후 호출. readAllData() }
3. Delete
import UIKit import CoreData class ViewController: UIViewController { //ViewController의 프로퍼티인 container가 Appdelegate에 있는 persistentConatiner를 참조하게 되는 과정 var container: NSPersistentContainer! override func viewDidLoad() { super.viewDidLoad() let appDelegate = UIApplication.shared.delegate as! AppDelegate self.container = appDelegate.persistentContainer // createData(name: "Jean", phoneNumber: "010-1111-2222") // // updateData(currentName: "Jean", updateName: "Yejin") // 아래에서 updateData라는 func를 만든 후 호출. deleteData(name: "Yejin") readAllData() }