Xcodeプロジェクト作成後にCoreDataを有効にする。


#〜.xcdatamodeldファイルを生成する。

プロジェクト作成時にCoreDataを有効にしている場合は自動で作成されてます。後から追加する場合はこのファイルが必須になります。CoreDataはコマンドラインやxmlを使わずに、このフォームベースでデータベースの情報が登録できます。そのためには.xcdatamodeldが必須になります。

右クリックからNew Fileを選択して

![スクリーンショット_2020-09-14_9_05_30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99731/1d8e49db-369c-beb5-4e40-487981777ac6.png)

下にスクロールしてCore DataのData Modelを選択してください。

![スクリーンショット_2020_09_14_9_08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99731/db5c3079-ee98-6cde-a575-31cfe11a8fef.png)

#保存したいデータの情報を登録する。

## EntityとAttribute

Entityにはどんな情報を管理したいのかわかるような名前をつけます。タスク管理ならTask、メモ帳ならMemoなど、表の題名をイメージするとわかりやすいです。

Attributeには、Entityに保存する情報の単位とデータ型を決めます。タスクを新規追加した時間(Date)、タスク名(String)、タスクの有効/無効(Boolean)など、表の列名をイメージするとわかりやすい。

![Model_xcdatamodel.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99731/b4448d0b-ae01-99ad-ede9-0dfeaf43ebc4.png)

## NSManagedObjectを継承したクラスを作成する。

先程のCoreDataに作ったEntityとAttributeをSwiftからアクセスしてオブジェクトとして利用するためにNSManagedObjectを継承したデータクラスを作成します。


〜.xcdatamodeldを選択した状態でEditor->Create NSManagedObject Subclass...を選択して
案内通りに進みます。




![スクリーンショット_2020-09-14_9_22_42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99731/bae2a9c2-554b-8eac-c4a4-81ec2ac4bca6.png)

Task+CoreDataClass.swiftとTask+CoreDataProperties.swiftが生成されます。

![ContentView_swift_と_「Xcodeプロジェクト作成後にCoreDataを有効にする。」を編集_-_Qiita.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99731/74a3fb28-35b7-d9ba-9002-80ca116ab6c9.png)


デフォルトの設定だと、NSManagedObjectを継承したクラスが存在しなくてもビルド時にxcodeが生成してくれますが、後々いろいろとやるために自分で作成して管理したほうが楽だと思いますので、この設定を無効にするためにcodegen(コードジェネレータ)をManual/Noneに変更します。

![Model_xcdatamodel_と_「Xcodeプロジェクト作成後にCoreDataを有効にする。」を編集_-_Qiita.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99731/77761a26-a8f7-eb5b-0eed-1fe04b0c4836.png)



リスト形式でデータを表示するためにIdentifiableを継承させます。

```Swift:Task+CoreDataProperties.swift

import Foundation
import CoreData


extension Task {

    @nonobjc public class func fetchRequest() -> NSFetchRequest<Task> {
        return NSFetchRequest<Task>(entityName: "Task")
    }

    @NSManaged public var id: UUID?
    @NSManaged public var name: String?
    @NSManaged public var isComplete: Bool
    @NSManaged public var dateAdded: Date?

}

//Identifiableに対応させるため追加
extension Task: Identifiable {
}

```

## AppDelegate.swift

CoreDataライブラリを読み込ませ

```Swift
import UIKit
import CoreData
```

###  AppDelegateクラスにpersistentContainerプロパティとsaveContextメソッドを追加

下のコードを追加します。

```Swift


 lazy var persistentContainer: NSPersistentContainer = {
         
           let container = NSPersistentContainer(name: "Model")
           container.loadPersistentStores(completionHandler: { (storeDescription, error) in
               if let error = error as NSError? {                    
                   fatalError("Unresolved error \(error), \(error.userInfo)")
               }
           })
           return container
       }()

       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)")
               }
           }
       }

```

NSPersistentContainerのnameに渡す文字列は.xcdatamodeldのファイル名になります。
自分が定義したファイル名に書き換えないとエラーになりますので注意してください。

Model.xcdatamodeldの場合

```Swift
let container = NSPersistentContainer(name: "Model")
```

## SceneDelegate.swift

CoreDataからデータを取得したり、新規データを追加するには、Contextが必要になります。ContentViewからContextを利用するためSceneDelegate.swiftを修正します。


```Swift
let contentView = ContentView()
```

を下に変更

```Swift

let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let contentView = ContentView().environment(\.managedObjectContext, context)

```

```Swift:ContentView.swift


import SwiftUI
import CoreData

struct ContentView: View {
    
    @Environment(\.managedObjectContext) var context
    
    @FetchRequest(
        entity: Task.entity(),
        sortDescriptors: [NSSortDescriptor(keyPath: \Task.dateAdded, ascending: false)],
        predicate: NSPredicate(format: "isComplete == %@", NSNumber(value: false))
    ) var notCompletedTasks: FetchedResults<Task>
    
    @State var newTaskName:String = ""
    
    func addTask(taskName: String, context: NSManagedObjectContext) {
        let task = Task(context: self.context)
        task.id = UUID()
        task.isComplete = false
        task.name = taskName
        task.dateAdded = Date()
        do {
            try self.context.save()
        } catch {
            print(error)
        }
    }
    
    func completeTask(_ task: Task, context: NSManagedObjectContext){
      let taskId = task.id! as UUID
        print(taskId)
      let fetchRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "Task")
      fetchRequest.predicate = NSPredicate(format: "id == %@", taskId as CVarArg)
      fetchRequest.fetchLimit = 1
      do {
        let tasks = try context.fetch(fetchRequest)
        let targetTask = tasks[0] as! NSManagedObject
        targetTask.setValue(true, forKey: "isComplete")
        try context.save()

        print(targetTask)
      } catch {
        print(error)
      }
    }
    
    var body: some View {
        
        VStack {
            TextField("タスクを入力してください。", text: $newTaskName, onEditingChanged: { _ in
            }, onCommit: {
                self.addTask(taskName: self.newTaskName, context: self.context)
                self.newTaskName =  ""
            })
                .keyboardType(.default)
                .textFieldStyle(RoundedBorderTextFieldStyle())
                .padding(32)
            
            List {
                ForEach(self.notCompletedTasks){ task in
                    Button(action: {
                        self.completeTask(task, context: self.context)
                    }) {
                        Text(task.name!)
                    }.onAppear() {
                        print(task.isComplete)
                    }
                }
            }
            
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

```