[iOS] Core Data 이용 데이터 관리하기 (1/2)

2020. 8. 26. 18:01iOS

반응형

이번에 최근 검색어 기능을 구현해야하는 프로젝트가 있었어요..‼️

 

최근 검색어의 경우에는 서버에서 주는 값이 아니고 사용자의 검색 기록이기 때문에 iPhone에 자체적으로 저장되어야 할 것 같더라구요

원래는 iPhone에 자체적으로 저장이 필요할 경우 UserDefualt을 사용해서 저장을 했었어요. 

 

근데 이번의 경우에는 최근 검색어를 10개만 가져오거나 시간 순으로 가져오거나 Model의 형식으로 저장이 되어야 하기 때문에, UserDefault로는 무리가 있다고 생각이 들었어요.

 

그렇기 때문에 Core Data을 한번 사용해봤습니다.

 

아... 저장하기 위해서 또 Core Data, Realm, FMDB등의 방법이 있더라구요..‼️

저는 우선 iOS 기본 프레임워크에 있는 것을 사용하고 싶어서 Core Data을 사용했어요.


Core Data란?

Apple 개발자 공식 사이트에 의하면 데이터를 유지하거나 캐쉬해야할 때, 이용할 수 있다고 되어 있어요.

또한 Core Data Model 에디터를 통해서 저장하기 위한 데이터 타입을 정의하고 그 사이에 관계를 맺고 테이블을 정의할 수 있어요.

RDB의 특징을 가진다고 이해하면 될 것 같습니다.

 

이것도 명심해주세요..‼️

Core Data는 프레임 워크입니다. 절대 DataBase는 아니에요.

 

이전 포스팅 iOS Architecture Layer에 대한 것을 참조해주세요

 

 

그렇다면, 저장하는 방법이 UserDefault을 이용하는 방법도 있는데 Core Data을 이용할때는 언제일까요..?!

뭔가 좀 더 복잡한 데이터가 필요하거나 이 데이터를 가져올 때, 특정 방식이 필요할 때 사용하면 좋아요.

 

이를 잘 활용해서 사용하면 유용할 것 같아요.

 

이제 이를 활용해서 사용하는 방법을 차근차근 알아볼까요⁉️

 

 

Core Data 사용하기

이미 프로젝트가 만들어져 있다고 가정하고 방법을 알려드리도록 할게요.

 

1️⃣프로젝트에서 Data Model 파일을 생성해주세요 (이름은 저는 최근 검색어라 RecentSearchModel이라고 생성해주었어요.)

 

 

2️⃣생성해준 Data Model 파일을 선택하고 Add Entity 버튼으로 Entity을 추가해주세요. (Entity는 하나의 객체 Model이라고 생각하면 될 것 같아요.)

 

3️⃣이제 생성해준 Entitiy에 본인의 저장할 데이터에 맞는 Property을 만들어주세요.

(저는 최근 검색어이기 때문에 검색한 일시와 고유 index, 검색어를 저장할 수 있게 3가지를 만들어주었어요.)

이건 본인에 맞게 설정하면 될 것 같아요.

 

4️⃣오른쪽 인스펙터 바에서 Manual/None을 선택해주세요.

 

5️⃣Manual/None을 선택했기 때문에, 해당 Model에 해당하는 객체를 직접 생성해주어야 해요.

Model을 클릭하고 Editor -> Create NSManagedObject Subclass을 선택해주세요.

 

이제 지금까지 잘 따라오셨으면 사용할 준비가 모두 끝이났어요.

한 번 이제 코드로 사용하는 방법들을 자세히 보도록할게요.

 

Core Data에 사용되는 객체들도 추가로 알고 이해하고 사용하면 좋지만,

오늘은 우선 사용방법만 알아보고 다음 포스팅에서 관계에 대해서는 자세히 알아보도록 할게요.

 

 

우선 앱 전역에서 Core Data에 접근할 수 있도록 NSPersistentContainer 객체를 먼저 생성해주도록 할게요.

사용할 곳에서 하나만 생성하셔도 됩니다.

import CoreData

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    // MARK: - Core Data
    lazy var persistentContainer: NSPersistentContainer = {
        // name: Core Data 만든 파일명 지정
        let container = NSPersistentContainer(name: "RecentSearchModel")
        container.loadPersistentStores(completionHandler: { (storeDescription, error) in
            if let error = error {
                fatalError("Unresolved error, \((error as NSError).userInfo)")
            }
        })
        return container
    }()
}

 

저는 Core Data을 관리하는 객체를 따로 만들고 싶어서 CoreDataManager로 만들어서 싱글톤으로 관리할 수 있게 했어요.

import UIKit
import CoreData

enum CoreDataName: String {
    case recentResearch = "RecentResearchTerm"
}

class CoreDataManager {
    static let shared: CoreDataManager = CoreDataManager()
    
    private let appDelegate = UIApplication.shared.delegate as? AppDelegate
    private lazy var context = appDelegate?.persistentContainer.viewContext
    
}

 

이제 Core Data에서 데이터를 가져오고 저장할 준비가 모두 끝이 났어요.

가장 간단한 저장하고 가져오는 코드를 작성해볼게요.

 

 

✔️저장

// MARK: - 해당 정보를 저장한다
func saveRecentSearch(term: String, date: Date, index: Int32, completion: @escaping (Bool) -> Void) {
    guard let context = self.context,
    	let entity = NSEntityDescription.entity(forEntityName: CoreDataName.recentResearch.rawValue, in: context)
    	else { return }

    guard let recentTerms = NSManagedObject(entity: entity, insertInto: context) as? RecentResearchTerm else { return }
    
    recentTerms.term = term
    recentTerms.date = date
    recentTerms.index = index

    do {
    	try context.save()
    	completion(true)
    } catch {
    	print(error.localizedDescription)
    	completion(false)
    }
}

코드를 보게 되면 Entity을 생성하는 코드가 가장 첫 줄에 있는게 보이죠⁉️

해당 Entitiy에 맞는 NSManagedObject을 생성해주고 그 객체의 값을 설정해주고 context.save() 을 호출해주면 됩니다.

 

이건 명심하셔야해요.

 

어떤 값을 바꾸거나 어떤 값을 저장할 때, context.save() 을 호출하지 않으면 런타임 중에는 값이 변하지만 Core Data에는 값이 반영되지 않아요.

 

이제 불러오기를 통해서 값이 저장되었는지 확인해주면 되겠죠⁉️

 

 

✔️불러오기

// MARK: - 저장된 모든 정보를 가져온다
func loadFromCoreData<T: NSManagedObject>(request: NSFetchRequest<T>) -> [T] {
    guard let context = self.context else { return [] }
    do {
        let results = try context.fetch(request)
        return results
    } catch {
        print(error.localizedDescription)
        return []
    }
}

저장하는 것은 각각의 값이 설정이 필요하기 때문에, Generic을 사용하기 힘들 것 같더라구요.

불러오기에서는 Generic을 이용해서 좀 더 코드를 이쁘게 짜봤어요..🙌

 

우선 context는 어떤 작업을 하던 필수랍니다..

 

여러분들 Model의 Class을 Maual하게 생성하셨던 거 기억하시나요⁉️

한번 그 생성된 Class의 구현부를 보게 되면 fetchRequest()라는 메소드가 자동 생성된 것을 볼 수 있어요.

코드를 보면 해당 entity에 맞는 NSFetchRequest 객체를 반환해주는 것을 알 수 있죠⁉️

 

그렇다면 loadFromCoreData(:_)을 불러줄 때 어떻게 호출하면 될까요?

let recentResearhTerms = CoreDataManager.shared.loadFromCoreData(request: RecentResearchTerm.fetchRequest())

다음과 같은 방법으로 호출하면 쉽게 데이터를 가져올 수 있답니다..‼️

 

 

다들 직접 확인해보세요~~~~

 

 

✔️ 삭제

// MARK: - 특정 index 번호 삭제
func delete<T: NSManagedObject>(at index: Int, request: NSFetchRequest<T>) -> Bool {
    request.predicate = NSPredicate(format: "index = %@", NSNumber(value: index))

    do {
    	if let recentTerms = try context?.fetch(request) {
            if recentTerms.count == 0 { return false }
            context?.delete(recentTerms[0])
            try context?.save()
            return true
        }
    } catch {
        print(error.localizedDescription)
        return false
    }

    return false
}

특정 index의 값을 Core Data Model에서 찾기 위해 정규식을 사용해서 우선 값을 가져왔어요.

 

데이터가 있는 경우 그 데이터를 삭제할 수 있게 구현했어요.

 

context.delete(recentTerms[0]) 후에 context.save()을 실행하는거 보이시나요⁉️

 

아까 이전에 데이터의 변경이 있었을 때, save을 호출하지 않으면 Core Data에 반영되지 않는다고 했던 거 기억하시죠.

꼭꼭 기억해주세요.

 

 

이상으로 오늘 Core Data에 대한 간단한 사용법을 다룬 포스팅을 끝낼게요 🙌

다음 포스팅은 Core Data을 관리하는 객체 간의 관계 설명에 대해 자세한 포스팅을 해볼게요

 

 

반응형