6
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

watnowAdvent Calendar 2023

Day 1

爆速CoreData

Last updated at Posted at 2023-11-29

はじめに

こんにちは、watnowのアドベントカレンダー初日を担当させていただきます。
よろしくお願いします!
記事を書くのは2回目なのでかなり拙い文章となっております、ご了承ください。:bow_tone1:

そしてこの記事は、

いち早くCoreDataを使いたい!!

そんな人向けの記事になっているので詳しいことは個人的に分かり易いなと思った記事を貼っておくので詳しくはそちらで学習してもらえればと思います。
では本題に移ります。

CoreDataってなに?(爆速)

CoreDataは、ローカルにデータを保存、取得などをするためのCocoaFrameWorkに搭載されたO\RマッパーのことでありDB自体はSQLiteを使っています。

O\Rマッパー
O\RマッパーとはオブジェクトとRDBをつなぐ橋渡しのようなもの
通常プログラムでインスタンスの値を保存するSQL文などを生成するコードを書かなければいけないが、O\Rマッパーはあらかじめ設定しておいた対応関係から自動でデータベースの対応するテーブルに書き出しや逆にデータを読み込みインスタンスに代入などをしてくれるというものです。

つまりXCode上で対応関係を設定すれば直接DBを管理しなくてもデータを保存、取得できるということ!

説明はこれくらいにして早速爆速CoreDataしましょう!

爆速CoreData

今回はCoreDataを使って、データの保存、取得、削除をできるメモアプリを作りながら説明していこうと思います。

セットアップ編

新しいプロジェクトを作成する場合
[File]->[New]->[Project]->Strage欄からCoreDataを選択して-> Next
スクリーンショット 2023-11-29 18.19.56.png
既にプロジェクトがある場合
[File]->[New]->[File...]でCoreDataのところまでスクロール

DataModel -> [Next]
タイトルは各々好きな名前を設定していただいて、Create!

するとこのようなファイルが生成されていると思います。
スクリーンショット 2023-11-29 18.46.40.png
後からCoreDataを追加した方はPersistence.swiftを追加し,

Persistence.swift
//
//  Persistence.swift
//  QiitaCoreData
//
//

import CoreData

struct PersistenceController {
    static let shared = PersistenceController()

    static var preview: PersistenceController = {
        let result = PersistenceController(inMemory: true)
        let viewContext = result.container.viewContext
        for _ in 0..<10 {



            // 各々のEntity名、Attribute名でカスタムしてください
            /*
             let newEntity名 = Entity名(context: viewContext)
             newEntity名.Attribute名 = 初期値
             */


            let newMemo = Memo(context: viewContext)
            newMemo.memo = ""
        }
        do {
            try viewContext.save()
        } catch {
            let nsError = error as NSError
            fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
        }
        return result
    }()

    let container: NSPersistentContainer

    init(inMemory: Bool = false) {
        container = NSPersistentContainer(name: "QiitaCoreData")
        if inMemory {
            container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null")
        }
        container.loadPersistentStores(completionHandler: { (storeDescription, error) in
            if let error = error as NSError? {
                fatalError("Unresolved error \(error), \(error.userInfo)")
            }
        })
        container.viewContext.automaticallyMergesChangesFromParent = true
    }
}

これをコピペしてください

ここからメモに必要な情報の登録をしていきます。
.xcdatamodelIdを選択し、
ENTITIES名をMemoに変更

初め大文字で書かないと注意されます。

Attribute欄の+ボタンを押し、ここに必要な情報とその型を設定します。
今回は文字列を保存するのでmemo: String

Atterbute名は小文字から始めないと注意されます。

timestampは今回使わないのでtimestampをクリックし − を押して消します。
右のEntityのcodegen欄はManual/Noneを選択します。
爆速なのでこの辺の詳細は、とてもわかりやすい記事があるので気になる方はそちらをみてください。
SwiftDataの前にCore Dataを学ぶ
そしてここで[Editor]->[Create NSManagedObject Subclass..]を選択します。

スクリーンショット 2023-11-29 21.14.36.png
するとこの画面に移るのでひたすら[Next]->[Next]->[Create]
スクリーンショット 2023-11-29 21.14.57.png
をすると
Memo+CoreDataClass.swift
Memo+CoreDataProperties.swiftが追加されます。
この辺の詳細もわかりやすい記事を貼っておきますので気になるかたはこちらから
やっとわかったSwift/CoreData入門
次にPersistence.swiftの17,18行目を編集します。
新しくプロジェクトを作った方は

            let newItem = Item(context: viewContext)
            newItem.timestamp = Date()

となっていると思いますので

             let newEntity名 = Entity名(context: viewContext)
             newEntity名.Attribute名 = 初期値
             //Memoエンティティで2つ以上のデータを扱う場合はこの下に同じように書く

と変更しておきます。
よって今回は

            let newMemo = Memo(context: viewContext)
            newMemo.memo = ""

とします。
最後に
プロジェクト名App.swiftに環境値として


managedObjectContext

役割 ・Entityのインスタンスを生成、管理
   ・persistanceStore(データベースの情報管理クラス)に変更を保存


をセットしておきます。

import SwiftUI

@main
struct QiitaCoreDataApp: App {
+        let persistenceController = PersistenceController.shared

    var body: some Scene {
        WindowGroup {
            ContentView()
+                .environment(\.managedObjectContext, persistenceController.container.viewContext)
        }
    }
}

これでセットアップは完了です!簡単なデータのみですがかなり簡単にセットアップができたと思います。

では次はデータの操作(取得、追加、削除)をしていこうと思います!

データ操作編

まず、CoreDataを利用したいViewに
managedObjectContextを ViewContext として
定義しておきます

 @Environment(\.managedObjectContext) private var viewContext

取得

データの取得は
@FetchRequestを使い、プロパティの
keyPathで基準とするデータを特定し,
ascendingでデータを昇順や降順にソートすることができます。
FetchedResultプロパティを使うことでデータを取得することができ、
memoListという名前で利用することができます。
今回は

ContentView.swift
 @FetchRequest(
        sortDescriptors: [NSSortDescriptor(keyPath: \Memo.memo, ascending: true)],
        animation: .default)
        private var memoList: FetchedResults<Memo>

とします。これでmemoListをfor文などで回して表示することができます。


追加

データの追加は

    private func addItem(memoString: String) {
        withAnimation {
            //Memoエンティティのインスタンスを初期化
            let newMemo = Memo(context: viewContext)
            newMemo.memo = memoString

            do {
                //データを保存
                try viewContext.save()
            } catch {
                let nsError = error as NSError
                fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
            }
        }
    }

で追加することができます。

try viewContext.save()

を忘れないようにしましょう。


削除

削除はdeleteItemsを使って削除します。
今回はonDeleteを使うのでoffSetからデータを特定して削除します。

    private func deleteItems(offsets: IndexSet) {
        withAnimation {
            offsets.map { memoList[$0] }.forEach(viewContext.delete)

            do {
                try viewContext.save()
            } catch {
                let nsError = error as NSError
                fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
            }
        }
    }

これらを用いると
screen.gif

このようなデータの取得、追加、削除ができるアプリを作ることができます。
ContentViewの全体を載せておきます。

ContentView.swift


//
//  ContentView.swift
//  QiitaCoreData
//

import SwiftUI
import CoreData

struct ContentView: View {
    @Environment(\.managedObjectContext) private var viewContext
    @FetchRequest(
        sortDescriptors: [NSSortDescriptor(keyPath: \Memo.memo, ascending: true)],
        animation: .default)
    private var memoList: FetchedResults<Memo>
    @State private var memoString: String = ""

    var body: some View {
        VStack {
            HStack {
                TextField("メモを入力", text: $memoString)
                    .frame(width: 300, height: 60)
                Button(action: {addItem(memoString: memoString)}, label: {
                    Text("追加")
                })
            }
                List {
                    ForEach(memoList) { item in
                        Text(item.memo ?? "")
                    }
                    .onDelete(perform: deleteItems)
                }

        }
        }


    private func addItem(memoString: String) {
        withAnimation {
            //Memoエンティティのインスタンスを初期化
            let newMemo = Memo(context: viewContext)
            newMemo.memo = memoString

            do {
                //データを保存
                try viewContext.save()
            } catch {
                let nsError = error as NSError
                fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
            }
        }
    }

    private func deleteItems(offsets: IndexSet) {
        withAnimation {
            offsets.map { memoList[$0] }.forEach(viewContext.delete)

            do {
                try viewContext.save()
            } catch {
                let nsError = error as NSError
                fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
            }
        }
    }
    }
#Preview {
    ContentView().environment(\.managedObjectContext, PersistenceController.preview.container.viewContext)
}

import CoreDataも忘れずに。
https://github.com/sawakishuto/qiitaCoreData

終わりに

爆速CoreData

いかがだったでしょうか、爆速で使えるようになりましたか?
とても単純な操作ではありますが、CoreDataの扱いの理解の手助けになっていれば嬉しいです。
また、登場クラスが多くあり、今回は説明を端折っている部分が多いので一つ一つの意味を深ぼると、より理解が深まるかと思います。
自分自身あまり理解できていない部分も多かったので、今回この記事を書いていて気づく点が多くとても良い機会になりました。
至らない点もあると思いますので、間違い等ありましたらぜひコメント等で訂正していただけると嬉しいです。


ちょっと宣伝

先日、個人開発していたアプリ
MoToBBS
をリリースすることができました!!!
ちょい乗り、キャンプツーリング、ミーティングなど、バイクのツーリングが誰でもどこでも手軽に募集、参加できるというアプリになっております!
ちなみにこのアプリにも
・自動ログインのためのログイン情報
・チュートリアル
・ブロックリスト
等にCoreDataを使用しています!
これからも機能追加、改善しますのでぜひダウンロードしてみてください!

ダウンロードはこちらから

MoToBBS

6
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?