徒然エンジニアブログ

徒然エンジニアブログ

理系東大生がプログラミングを中心に様々なことについて情報発信していきます!

【Swift】CoreDataを使ったデータの保存を一から解説!

Swiftでアプリを作る時にデータを保存する方法はいくつかあります。
その中で今回はCoreDataを使ったデータの保存について見ていきたいと思います。

例としてタスク管理アプリを作っていることにします。
やることの名前と期限の二つの値を持つとします。

CoreDataを使うときの設定

use CoreDataにチェックをつける

これはprojectの開始時にuse coreDataというところにチェックをつけておくだけです。
すると、AppDelegate.swiftの中にCoreData関連のコードが自動で追加されます。

自分で記述することも不可能ではありませんが圧倒的に楽なので忘れずにチェックをしておくようにしましょう。

EntityとAttributesの設定

拡張子がxcdatamodeledというファイルを選んでクリックします。
まず左下の方にある+ノボタンからentityを登録します。クラスみたいなものだと思ってください。
ここでは名前をTaskとします。


Entityを選択すると、右側にManual/None, Class Definition Category/Extentionがあると思うのでそこをClassDefinitonとしておいてください。
こうすると見えないところで自動的にクラスを作ってくれます。

そして次にattributeを作ります。名前はnameとtimeLimitとして二つともString型にしてください。
optional型が良いので右側に出てくるところにあるoptionalにもチェックを入れましょう。

f:id:turedureengineer:20181207225357p:plain

見にくいですが上のような図になってれば良いです。
これで準備は終わりです。

実際に使ってみる

データを保存する

まずは基礎としてデータの保存の仕方を見ていきましょう。

//ここは丸写しで良い
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
//インスタンス化をする
let task = Task(context: context)
task.name = "入れたい文字列"
task.timeLimit = "入れたい文字列"

//保存する
(UIApplication.shared.delegate as! AppDelegate).saveContext()

これだけでデータを保存することができます。
最初の一文目が難しいですがそのままコピペで大丈夫です。

データを読み込む

書き込んだ後は読み取りですね。
コードは以下のようになります。

let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
        do {
            // CoreDataからデータをfetchしてtasksに格納
            let fetchRequest: NSFetchRequest<Task> = Task.fetchRequest()
            tasks = try context.fetch(fetchRequest)
            
        } catch {
            print("Error")
        }

ここでtasksはTask型の配列です。取得したデータもTask型の配列なのでここに入れることができます。
do-catchの中に書くことでエラー処理をしています。

データを削除する

データを読み込むときのコードを少し変更すればできます。
まずコードを見て見ましょう。

 // 削除したいデータの名前とタイムリミットを宣言する。
let deletedName = tasks[indexPath.row].name            
let deletedTimeLimit = tasks[indexPath.row].timeLimit
// 先ほど取得したcategoryとnameに合致するデータのみをfetchするようにfetchRequestを作成
let fetchRequest: NSFetchRequest<Task> = Task.fetchRequest()
//ここを付け加えるだけ
fetchRequest.predicate = NSPredicate(format: "name == %@ and timeLimit == %@",deletedName!, deletedTimeLimit!)
    do {
         let task = try context.fetch(fetchRequest)
         context.delete(task[0])
    } catch {
         print("Fetching Failed.")
    }
    // 削除したあとのデータを保存する
    (UIApplication.shared.delegate as! AppDelegate).saveContext()

まず消したいデータの名前や期限を宣言します。
今回はタップされたセルの名前と期限を取得してそれらの名前を持つデータを消していきたいと思います。


読み取るときは何も考えずに全てのデータを取得しましたが今回は条件に合致するものだけを取得します。
それがNSPredicate(format: "name == %@ and timeLimit == %@",deletedName!, deletedTimeLimit!)の部分です。
右側二つの変数が%@のところに文字列として代入されます。


context.fetch(fetchRequest)は条件に合致するTask変数全て返してきます。
要するに今回のtaskはTask型の配列です。

今回はこの配列に一つしか入っていないと想定しているため、task[0]を消去するとして終わりです。


データベースをいじったときは保存を忘れないようにしましょう。

取得したデータはUITableViewなどで表示させることが多いと思います。
その時に使えるカスタムセルについて以下の記事で紹介しているのでみてみてください。
turedureengineer.hatenablog.com