티스토리 뷰

iOS

iOS) CoreData 사용하기 (CRUD 구현)

Ekko0701 2022. 8. 28. 15:36

Core Data란?

 Core Data는 단일 기기 앱의 오프라인 환경에서 영구적인 데이터를 저장하고, 임시 데이터를 캐시 한다. 그리고 앱에 실행 취소 기능을 추가한다. iClound를 사용해 여러 기기의 데이터를 동기화할 수 있다.

 

 Core Data의 데이터 모델 에디터를 통해 데이터의 타입과 관계를 정의할 수 있고 각각의 클래스 정의를 생성한다. 그러면 런타임에 객체 인스턴스를 관리하며 다음과 같은 기능을 제공한다.

• Persistence
• Undo and Redo of Individual or Batched Changed
• Background Data Tasks
• View Synchronization
•Versioning and Migration

 

Apple Developer Documentation

 

developer.apple.com

 Core Data를 처음 접했을 때는 Data Base인 줄 알았다. 하지만 Core Data는 Data Base가 아니다. Core Data는 애플리케이션의 모델 계층의 객체를 관리하는데 사용하는 Framework이자 객체의 라이플 사이클이나 영속성 관리를 위한 기능을 제공하는 객체 그래프 관리자이다. Core Data에서 제공하는 기능 중 Persistence는 관계형 데이터 베이스인 SQLite에 의해 지원되는데 이 기능을 사용해 데이터를 영구적으로 저장하는 것이다.

 

 간단한 단일 데이터를 영구적으로 저장할 때 UserDefaults를 이용했다면 복잡한 데이터를 저장할 때는 Core Data가 적합하다.

 


그럼 Core Data를 사용해보자.

프로젝트를 생성할 때 Use Core Data를 체크해주자.

 

만약 이미 존재하는 프로젝트에 Core Data를 추가하고 싶다면

Data Model이라는 파일을 새로 만들어 추가할 수도 있다.

 

그럼 위와 같은 파일이 생성된 걸 볼 수 있다.

 

이제 데이터의 집합인 Entity를 추가해주자.

 

Entity를 추가하면 다음과 위와 같은 화면이 나온다.

 

Entity의 이름을 바꿔주자. Entity의 이름을 사용해 접근하기 때문에 기억해야 한다.

 

그리고 Entity의 속성을 추가해주자.

 

Item이라는 Entity에 title이라는 String 타입의 속성과 check이라는 Boolean 타입의 속성을 추가해 주었다.

( To do 처럼 만들어 볼 건데 title은 할 일, check는 수행 여부이다. ) 

 

Entity를 선택 후 인스펙터에서 Codegen을 보자.

간단하게 옵션들을 살펴보자면 다음과 같다. 참고

 

Manual/None - (두 파일 모두 수동으로 관리)

 관리 개체 서브 클래스의 속성을 편집할 수 있다. 예를 들어 Access Modifier를 변경하고 추가 편의 메서드 또는 비즈니스 로직을 추가한다. 이 옵션을 선택하면 xcode에서 개체를 관리하기 위한 파일을 생성해주지 않는다. 클래스 파일과 속성 파일을 수동으로 생성해야 한다.

 

Class Definition - (두 파일 자동 생성)

 Core Data가 생성한 관리 개체 서브 클래스나 속성 파일들의 속성, 기능을 편집할 필요가 없는 경우에 선택한다. 생성된 소스 코드는 프로젝트의 소스 목록에 나타나지 않고, 엔티티가 변경될 때마다 자동으로 다시 생성된다.

 

Category/Extension - (속성 파일만 생성)

 관리 객체 서브클래스에 편의 메서드 또는 비즈니스 로직을 추가할 때 선택한다. 이 옵션은 클래스 파일을 완전히 제어하며 속성 파일을 계속 자동으로 생성하며 업데이트한다.

 

이번에는 Manual/None을 선택하자.

 

위에서 기술했듯이 Manual/None 옵션을 선택했을 경우에 클래스 파일과 속성 파일을 수동으로 생성해줘야 한다.

 

Editor - Create NSManagedObject Subclass..

 

클래스와 속성 파일 생성 완료! 

 

 

AppDelegate.swift로 가보자.

프로젝트를 생성할 때 Use Core Data에 체크했다면 다음과 같은 코드가 있을 것이다.

없다면 AppDelegate 내부에 추가해주고 CoreData를 import 해주자.

// MARK: - Core Data stack
// import CoreData

    lazy var persistentContainer: NSPersistentContainer = {
        /*
         The persistent container for the application. This implementation
         creates and returns a container, having loaded the store for the
         application to it. This property is optional since there are legitimate
         error conditions that could cause the creation of the store to fail.
        */
        let container = NSPersistentContainer(name: "DataModel")
        container.loadPersistentStores(completionHandler: { (storeDescription, error) in
            if let error = error as NSError? {
                // Replace this implementation with code to handle the error appropriately.
                // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
                 
                /*
                 Typical reasons for an error here include:
                 * The parent directory does not exist, cannot be created, or disallows writing.
                 * The persistent store is not accessible, due to permissions or data protection when the device is locked.
                 * The device is out of space.
                 * The store could not be migrated to the current model version.
                 Check the error message to determine what the actual problem was.
                 */
                fatalError("Unresolved error \(error), \(error.userInfo)")
            }
        })
        return container
    }()

    // MARK: - Core Data Saving support

    func saveContext () {
        let context = persistentContainer.viewContext
        if context.hasChanges {
            do {
                try context.save()
            } catch {
                // Replace this implementation with code to handle the error appropriately.
                // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
                let nserror = error as NSError
                fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
            }
        }
    }

NSPersistantContainer(name: ) 에는 코어 데이터 파일 이름을 써주자. 프로젝트를 생성할 때 Use Core Data를 선택했다면 초기 파일 이름으로 되어있다. 파일 이름을 변경했다면 꼭 바꿔주자.

 

이제 CoreData를 사용하기 위한 사전 작업을 마쳤으니 CRUD를 구현해보자.

 

CoreData 사용 과정은 다음과 같다

1. PersistantContainer에서 NSManagedObjectContext를 가져온다.

2. Entity를 가져온다.

3. NSManagedObject 설정

4. NSManagedObjectContext에 저장

 

ViewController.swift에서 CRUD를 구현해보자.

Create

1. PersistantContainer에서 NSManagedObjectContext를 가져온다

let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext

 

2. Entity를 가져온다

let entity = NSEntityDescription.entity(forEntityName: "Item", in: context)

 

3. Object (Item) 설정

if let entity = entity {
            let item = NSManagedObject(entity: entity, insertInto: context)
            item.setValue(title, forKey: "title")
            item.setValue(false, forKey: "check")
        }

 

4. NSManagedContext에 저장

do {
     try context.save()
   } catch {
     print("Save Error : \(error)")
   }

 

전체 코드 

 

이때 2번 3번 과정을

let newItem = Item(context: context)
newItem.title = title
newItem.check = false

이런 식으로 작성해도 된다.

 

데이터를 저장했으니 저장한 데이터를 읽어보자.

Read

var itemArray = [Item]()

func loadItem() {
	do {
            itemArray = try context.fetch(Item.fetchRequest())
        } catch {
            print("Load Error : \(error)")
        }
}

 

 

itemArray에 fetch한 데이터(Item)들을 넣어주었다.

 

viewDidLoad()에서 saveData와 loadItem을 호출했다.   ( saveItem으로 할걸.. ㅋㅋ)

데이터를 로드한 후 for문으로 print 해서 확인해보자.

 

3번 실행한 결과이다.

잘 동작한다.

 

Update

func updateItem(item: Item, newTitle: String) {
        item.title = newTitle
        do {
            try context.save()
        } catch {
            print("Save Error : \(error)")
        }
    }

Update는 Create와 비슷하다. 변경하고 싶은 Item Object를 수정하고 다시 context를 저장해주면 된다.

 

테스트 결과

 

Delete

func deleteItem(item: Item) {
        context.delete(item)
        do {
            try context.save()
        } catch {
            print("Delete Error: \(error)")
        }
    }

Delete는 context에서 item을 삭제 후 다시 context를 저장해 주자.

 

추가로 전체 Items을 삭제하는 방법이다.

func deleteAllItems() {
        let request: NSFetchRequest<NSFetchRequestResult> = Item.fetchRequest()
        let delete = NSBatchDeleteRequest(fetchRequest: request)
        
        do {
            try context.execute(delete)
        } catch {
            print("Delete All error : \(error)")
        }
    }

context.save가 아니라 fetchRequest()를 받아와서 context.excute() 해주는 것에 주목하자.

 

 

여기까지 CoreData를 사용해 CRUD를 구현해 보았다. 다음에는 Realm에 대해 공부해보자. 🥳


Reference

https://sihyungyou.github.io/iOS-coredata/

https://ios-development.tistory.com/89

https://zeddios.tistory.com/987

https://icksw.tistory.com/224

http://yoonbumtae.com/?p=3865 

 

'iOS' 카테고리의 다른 글

iOS) UIView에 Border 적용하기  (0) 2022.09.01
iOS) Realm 사용하기  (0) 2022.08.30
iOS) UserDefaults 사용해 데이터 저장하기  (0) 2022.08.25
iOS) CocoaPods - pod install error 해결방법  (0) 2022.08.23
iOS) CocoaPods 사용하기  (0) 2022.08.23
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/07   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
글 보관함