IOS

[iOS] CoreData C.R.U.D

  안녕하세요 이번에는 CoreData에 대해서 글을 작성해 보겠습니다. 처음 CoreData라는 단어를 봤을때 오 정말 중요하고 좋은 저장 방법인가보다 해서 제가 이걸 몰랐을때 다른분이 이런걸 활용했다 할때는 그분이 정말 멋있어(?) 보이기도 했습니다.

이번에 날씨어플을 개발하면서 이거한번 꼭 써봐야겠다라고 생각한게 CoreData입니다. 사실 날씨어플에는 맞지않는 감이 있었지만 한번 꼭 써보고 싶었기에 도전해 봤었고 여러 난관에 부딫히기도 했지만 좋은 경험을 한것 같습니다.

CoreData의 특징

  1. 데이터를 디바이스에 영구적으로 저장할수 있습니다. ( 일시적인 데이터에는 적합하지 않습니다. )
  2. CoreData는 FrameWork 입니다. ( DataBase가 아닙니다 )
  3. CoreData의 기능중 하나인 Persistence는 관계형 데이터베이스인 SQlite에 의해 지원됩니다. ( Coredata의 기능인 영구 저장을 활용하는 것일뿐 DataBase가 아닙니다)
  4. 넓은 의미로 앱의 모델 계층이며, 객체 그래프를 관리하는 Framewrok입니다.

CoreData 사용법

  1. 프로젝트를 생성할때 Use Core Data를 체크해주셔야 합니다.

  1. 체크해서 생성하게 되면 이런모양의 파일이 생성됩니다

  1. 파일을 눌러보시면 처음보는 화면이 나오는데 화면 왼쪽에 보시면 Add Entity를 눌러줍니다. 이버튼은 코어데이터에 저장될 객체클래스를 생성하는 역할을 합니다. 이렇게 누르시면 이렇게 생성한 객체들이 보입니다.

  1. 그리고 화면 오른쪽 아래 Add Attribute를 누르시면 Attribute를 생성할수 있습니다.

    생성을 하면 Attribute가 추가되고 화면 오른쪽 사이드에 Data Model Inspector에서 속성을 세팅할수 있습니다. 이름과 타입을 선택하고 옵셔널이 체크되어 있는지 확인합니다.

  1. 이렇게 원하는 타입과 이름을 설정했으면 Editor → Create NSManagedObject Subclass를 누르면 CoreData에서 생성한 객체와 프로퍼티가 swift파일 형태로 생성됩니다

CoreData 이용하기

  • 먼저 알아두어야 할것은 데이터를 읽는 과정을 알아야 합니다. 코어데이터 프레임워크가 데이터를 저장하는방법은 UIApplication.shared.delegate as? AppDelegate 에 접근한후 appDelegate?.persistentContainer.viewContext 영구저장 영역에 저장을 하게 됩니다.
    이제 여기서 부터는 지정한 Entity를 이용해서 객체에 접근을 시도합니다.
    let dataFetchRequest = NSFetchRequest(entityName: "DataLocation")
    이런 형태입니다.

  • 공통되게 사용되는 데이터는 미리 프로퍼티로 빼서 선언해 두었습니다.

      let dataLocationModelName: String = "DataLocation"
      private let appDelegate: AppDelegate? = UIApplication.shared.delegate as? AppDelegate
      lazy var context = appDelegate?.persistentContainer.viewContext
      private let dataFetchRequest = NSFetchRequest<NSManagedObject>(entityName: "DataLocation")

CoreData Save ( Or Update )

  • 제가 코어데이터를 활용하면서 어려웠던 점은 저장하는 방법을 소개한 글은 많은데 정작 중복된 데이터를 저장함에 있어서 어떻게 거르고 같은 데이터가 있다면 그냥 업데이트만 할수는 없는 지를 많이 고민했습니다. 그래서 전달된 데이터를 저장하기전에 사용자가 지정한 데이터와 같은 객체가 저장되어있다면 그객체를 불러와서 데이터를 업데이트 하고, 없다면 그냥 저장하는 식으로 코드를 작성했습니다
func saveORUpdateDataLocation(_ location: Location ) {
    // 해당 객체에 접근합니다 
        let entity = NSEntityDescription.entity(forEntityName: dataLocationModelName, in: context!)
    //검색하는 키워드를 등록해주었습니다
        let filter = filteredDataLocationRequest(lattitude: location.latitude)

        do {
                // datas에는 만약 똑같은 키워드를 가진 데이터가 있다면 값이 담기고 없다면 빈배열이 담깁니다
            let datas = try context!.fetch(filter) as! [NSManagedObject]
            var cell: DataLocation! = nil
                // 검색된 데이터가 없는경우
            if datas.count == 0 {
                // 새로운 셀생성
                cell = NSManagedObject(entity: entity!, insertInto: context!) as? DataLocation
            } else {
                // 검색된 데이터가 있는경우 검색된 데이터를 호출
                cell = datas.first as? DataLocation
            }
            cell.latitude = location.latitude
            cell.longitude = location.longitude
            cell.stateName = location.name ?? ""
        } catch {
            print("Failed")
        }

        do {
            try context?.save()
            print("Save Succes")
        } catch {
            print("Failed To Saving")
        }
    }

// 이 매서드는 해당 객체에 접근해서 predicate를 통해 같은 데이터가 있는지 찾습니다. 찾는 키워드는 String을 입력해주어야 합니다. 

fileprivate func filteredDataLocationRequest(lattitude: Double) -> NSFetchRequest<NSFetchRequestResult> {
  let fetchRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest<NSFetchRequestResult>(entityName: dataLocationModelName)
  fetchRequest.predicate = NSPredicate(format: "latitude = %@", "\(lattitude)")
        return fetchRequest
    }

CoreData Load

  • Load는 말그대로 저장된 데이터를 가져오는 것입니다.

      func getDataLocationList() -> [Location] {
                 var models = [Location]()
    
                  do {
                      if let result: [DataLocation] = try context?.fetch(dataFetchRequest) as? [DataLocation] {
                              // result를 제가원하는 데이터 형태로 바꾸어서 리턴해줍니다. 
                        models = result.map { Location(name: $0.stateName ?? "" , latitude: $0.latitude, longitude: $0.longitude) }
                         }
                     } catch let error as NSError {
                         print("Could not fetch: \(error), \(error.userInfo)")
                     }
              return models
              }

CoreData Delete

  • 데이터를 삭제할때에는 하나의 타겟 키워드를 정해서 그 키워드를 사용해 데이터를 검색하고 일치하는 데이터를 삭제합니다.
// 이 매서드는 같은 lattitude를 가진 데이터를 찾아 삭제해줍니다. 
func deleteDataLocation(lattitude: Double) {
        let deleteRequest: NSFetchRequest<NSFetchRequestResult> = filteredListLocationRequest(lattitude: Double)
            do {
                if let results: [DataLocation] = try context?.fetch(deleteRequest) as? [DataLocation] {
                if results.count != 0 {
                             context?.delete(results[0])
                           }
                       }
                   } catch let error as NSError {
                       print("Could not fatch: \(error), \(error.userInfo)")
                   }
            do {
                    try context?.save()
                    print("코어데이터 삭제 성공")
                    return
                } catch {
                    context?.rollback()
                    print("실행 불가능 합니다")
                    return
                    }
        default: break
        }
    }

fileprivate func filteredDataLocationRequest(lattitude: Double) -> NSFetchRequest<NSFetchRequestResult> {
  let fetchRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest<NSFetchRequestResult>(entityName: dataLocationModelName)
  fetchRequest.predicate = NSPredicate(format: "latitude = %@", "\(lattitude)")
        return fetchRequest
    }

CoreData All Delete

func deleteAllDataLocation() {
        let fetrequest = NSFetchRequest<NSFetchRequestResult>(entityName: dataLocationModelName)
        // Batch는 한꺼번에 데이터처리를 할때 사용합니다. 지금의 경우 저장된 데이터를 모두 지우는 것입니다. 
        let batchDeleteRequest = NSBatchDeleteRequest(fetchRequest: fetrequest)

        do {
            try context?.execute(batchDeleteRequest)
            print("데이터 모두 삭제")
        } catch {
            print(error)
        }
    }

'IOS' 카테고리의 다른 글

[iOS] Google Place Autocompletion ( 검색 자동완성 )  (0) 2021.01.11
[iOS] Filemanager with Image Download  (0) 2021.01.11
[TIP] iOS, Swift 개발자 Road Map  (0) 2020.09.29