광어네 맛집

[CoreData]CURD 사용해보기 _ 01 본문

Swift/About Swift

[CoreData]CURD 사용해보기 _ 01

Lautner Jacob 2022. 5. 30. 12:46
728x90
반응형

SwiftUI도 어느정도 본 것 같고

심화로 들어가다 보니 SwiftUI 한계에 부딪히게 되는 것 같다

그래서 사용하게 된 CoreData!

 

물론 Realm 쓰면 간단하게 사용할 수 있는데 

라이브러리를 많이 쓰면 안좋으니까!


 

처음에 Xcode를 만들 때 CoreData 체크 후 만들면 

AppDelegate에 아래 처럼 자동으로 생기게 된다!

// MARK: - Core Data stack
lazy var persistentContainer: NSPersistentContainer = {
  let container = NSPersistentContainer(name: "test")
  container.loadPersistentStores(completionHandler: { (storeDescription, error) in
    if let error = error as NSError? {
      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 {
      let nserror = error as NSError
      fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
    }
  }
}

 

첫번째 [MARK] CoreData Stack의 경우 수동으로 만들 때 필수!

두번째 [MARK] saveContent의 경우 선택임!

 

먼저 들어가기 전에 saveContent는 어디에 쓰는지 알아봅시다!

바로 SceneDelegate에서 띠용 나옵니다 

앱이 'Background'로 들어가면 저장해준다...

많이 섬세하네요 ㅎㅎㅎ

func sceneDidEnterBackground(_ scene: UIScene) {
  (UIApplication.shared.delegate as? AppDelegate)?.saveContext()
}

 

그럼 다시 첫번째 [MARK] 로 돌아오면

여기 부분을 확인해줘야 합니다!

 

이 부분은 이름은 누구 이름이냐면 

아래 파일 이름입니다!

 

위 xcdatamodeld에 들어가면 'Entity', 'Attribute', 'RelationShips'을 설정할 수 있음!

Entity를 클릭하고 우측 인스펙터를 눌러보면 'Codegen'이 나옴!

 

현재는 자동으로 관리해주기 때문에 'Class Definition'에 체크 되어 있지만

수동으로 해주고 싶으면 'Manaual/None'을 체크하고

Xcode 상단 Editor -> Create NSManagedObject Subclass..해줌

 

아래처럼 파일 2개가 생긴걸 확인할 수 있습니다!

 


 

이제 30% 한 듯? ㅎㅎ

(힘내세열 ㅋㅋㅋ쿠ㅜㅜ)

이제 CURD를 설정할텐데 여러 블로그 찾아보다가

Manager로 빼서 사용하시는 글을 보고 참고 했습니다!

 

일단 Manager Class를 하나 만들어주고 다음과 같이 선언해줍니다

// Manager 사용하기 위한 Shared 작성
static let shared = CoreDataManager()

// 내부에서 사용하기 위한 'Entity'문자열
private let contactName: String = "Contact"

// AppDelegate 및 viewContext 선언
let appDelegate = UIApplication.shared.delegate as? AppDelegate
lazy var context = appDelegate?.persistentContainer.viewContext

 

정보 얻기

func getUsers() -> [Contact] {
  var models = [Contact]()
  if let context = context {
    let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: contactName)
    
    //정렬하기!
    //let idSort: NSSortDescriptor = NSSortDescriptor(key: "id", ascending: false)
    //fetchRequest.sortDescriptors = [idSort]
           
    do {
      if let fetchResult = try context.fetch(fetchRequest) as? [Contact] {
        models = fetchResult
      }
    } catch let error as NSError {
      print("Could not fetch: \(error), \(error.localizedDescription)")
    }
  }
  return models
}

 

저장하기

func saveUsers(starButton: Bool, name: String, onSuccess: @escaping (Bool) -> ()) {
  if let context = context, let entity = NSEntityDescription.entity(forEntityName: contactName, in: context) {
    if let users = NSManagedObject(entity: entity, insertInto: context) as? Contact {
    // Attribute 입력!
      users.starButton = starButton
      users.name = name
                
      contextSave { success in
        onSuccess(success)
      }
    }
  }
}

 

삭제하기!

(근데 Objective C 공부하고 오니까 NS코드가 보이네ㅋㅋㅋㅋ)

func deleteUser(name: String, onSuccess: @escaping (Bool) -> ()) {
  let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: contactName)
  fetchRequest.predicate = NSPredicate(format: "id = %@", NSString(string: name))

  do {
    if let results = try context?.fetch(fetchRequest) as? [Contact] {
      // 또는 context?.delete(results.first!)
      if !results.isEmpty { context?.delete(results[0]) }
    }
  } catch let error as NSError {
    print("Cloud not save: \(error), \(error.userInfo)")
    onSuccess(false)
  }
        
  contextSave { success in
    onSuccess(success)
  }
}

 

그리고 저장, 삭제 맨 마지막에 contextSave가 뭐지 했을거임!

이건 다음과 같음!

func contextSave(onSuccess: (Bool) -> ()) {
  do {
    try context?.save()
  } catch let error as NSError {
    print("Cloud not save: \(error), \(error.userInfo)")
    onSuccess(false)
  }
}

 

길고 길었던 CRUD가 완성되었습니다! ㅜㅜ

 


 

그러면 어떻게 사용하는지 볼까요?

func getCoreData() {
  let contact = CoreDataManager.shared.getUsers()
  let name = contact.map { $0.name }
}
    
func saveCoreData(_ name: String, starButton: Bool) {
  CoreDataManager.shared.saveUsers(starButton: starButton, name: name) { onSuccess in
  }
}
    
func deleteCoreData(_ name: String) {
  CoreDataManager.shared.deleteUser(name: name) { onSuccess in
  }
}

 


이렇게 사용하시면 됩니다!

길고 길었던 CoreData....

하지만 Relationship도 있고, 마이그레이션도 추가 포스팅할 거 같지만 

제 이슈 및 확인한 걸 공유하면서 마치도록 하겠습니다!

 


 

따라하시다가 제 Entity와 Attribures 가 어떤건지 궁금하실 수도 있으니까!

(추가로 개인적인 생각인데 id = UUID().uuidString 하면 식별자로 활용할 수 있을거에요

근데 UUID가 기기의 경우 앱 삭제하고 재설치하면 달라진다고 .. 이건 따로 Date로 해주는 것도 좋아보여요!

방법은 다양하고 저도 개린이니까 ㅎㅎ.. 좋은 방법있으면 추천 부탁드려요)

 


 

그리고 블로그들 보고 따라하다가 CoreData가 Queue로 되어 있던데?

나만 처음 알았나?ㅋㅋㅋㅋ라고 생각했다가 필터로 첫번째를 선택해줘서 그런거 였음...

 

만약 삭제할 때 필터를 주지 않으면 id 값을 주지 않고

name( String ), starButton ( Bool )만 가지고 CoreData를 만들었을 때

다 동일한 이름 모두가 삭제 ㅋㅋㅋㅋㅋ

 

무튼 여러 삽질을 하면서 한 고개 넘은 CoreData 였습니다!

 

그럼 오늘도 화이팅!

 

1. [CoreData]CURD 사용해보기 _ 01

2. [CoreData] 구조 및 위치에 대해서 _ 02

3. [CoreData] Relationships (+ SQLiteBrowser) _ 03

4. [CoreData] Migration _ 04

 

 

 

728x90
반응형