[1]iOSアプリ開発でGRDB.swiftを使う(環境構築編)

# 概要

今回は、iOSアプリ開発でローカルストレージを使用するため、"GRDB"を使ったサンプルを作ってみた

## GRDBってなに？

iOS アプリ開発において SQLite を扱いやすくするためのライブラリ(ラッパークラス)
要は JDBC とか 、.NET の System.Data.SQLite みたいなもので
クライアント言語によりそった簡易なデータベース接続と操作 API を提供してくれる。

## CocoaPodsってなに？

iOS/Mac向けのアプリを作成する際のライブラリ管理をしてくれるもの。
.Netでいう「Nuget」、pythonでいう「pip」とかそんな感じ

[iOSライブラリ管理ツール「CocoaPods」の使用方法](https://qiita.com/satoken0417/items/479bcdf91cff2634ffb1)

## 準備

1. pod init[←で、Podfileを生成する]
1. vim Podfile
1. pod 'GRDB.swift'　→　pod install
1. {Project Name}.xcworkspace　をクリック

以下、Podfileの記載例

```shell
target 'Mock'{application name} do
  # Comment the next line if you don't want to use dynamic frameworks
  use_frameworks!

  # Pods for Mock
  pod 'GRDB.swift'
end
```

## 全体ソース

XXXX.sqliteファイルは、プロジェクトの直下でよい

```swift
import Foundation
import GRDB

class DatabaseManager {
    
    let databaseFile: String!
    init(){
        databaseFile = NSHomeDirectory() + "/Documents/" + "taisaku.sqlite"
    }
    /*
     データベースファイルをコピーする処理
     マスターデータファイルをアプリ実行時のディレクトリにコピーする
     */
    func createDatabase(){
        let fileManager = FileManager.default
        guard let documentsUrl = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first else { return }
        let finalDatabaseURL = documentsUrl.appendingPathComponent("taisaku.sqlite")
        do {
            if !fileManager.fileExists(atPath: finalDatabaseURL.path) {
                print("DB does not exist in documents folder")
                if let dbFilePath = Bundle.main.path(forResource: "taisaku", ofType: "sqlite") {
                    try fileManager.copyItem(atPath: dbFilePath, toPath: finalDatabaseURL.path)
                } else {
                    print("Uh oh - foo.db is not in the app bundle")
                }
            } else {
                print("Database file found at path: \(finalDatabaseURL.path)")
            }
        } catch {
            print("Unable to copy foo.db: \(error)")
        }
    }
    
    /*
     init データ取り込み前にローカルDBの中身を初期化（DEL）する処理
     */
    func initDatabase(){
        let queue = try! DatabaseQueue(path:  self.databaseFile)
        try! queue.write({ (db) in
            try! db.execute(sql: "DELETE FROM taisaku;")
        })
    }
    
    func entryTaisakuData(taisakus : [Taisaku]){
        for taisaku in taisakus {
            
        }
    }
    
    /// 本メソッドをCALLすると、「"taisaku"テーブルに、"name"カラムに"hoge"を設定し、Insertする」
    func testInsert(){
        let queue = try! DatabaseQueue(path:  self.databaseFile)
        try! queue.write { (db) in
            do {
                var user = try User(name: "hoge")
                try! user.insert(db)
                print(user.id)
            // Optional(1)
            } catch {
                
            }
        }
    }

    // DB操作用クラス
    class User: Record {
        var id: Int64?
        var name: String
        var description: String
        var issueId: String
        let issueName: String

        // テーブル名
        override static var databaseTableName: String {
            return "taisaku"
        }

        enum Columns {
            static let id = Column("id")
            static let name = Column("name")
            static let age = Column("description")
            static let score = Column("issueId")
            static let createdAt = Column("issueName")
        }

        init(name: String) {
            self.name = name
            self.description = ""
            self.issueId = ""
            self.issueName = ""
            super.init()
        }

        required init(row: Row) {
            self.id = row["id"]
            self.name = row["name"]
            self.description = row["description"]
            self.issueId = row["issueId"]
            self.issueName = row["issueName"]
            super.init(row: row)
        }

        override func encode(to container: inout PersistenceContainer) {
            container["id"] = self.id
            container["name"] = self.name
            container["description"] = self.description
            container["issueId"] = self.issueId
            container["issueName"] = self.issueName
        }

        override func didInsert(with rowID: Int64, for column: String?) {
            // Insert時にidに反映
            self.id = rowID
        }
    }
}
```

使用例

```swift

@IBAction func btnTapped(_ sender: Any) {
　　// newする
    var databaseManager = DatabaseManager()
    databaseManager.testInsert()
}
```
## 注意点

一度作っている[build -> run]とうまくコピーされず空のsqliteファイルが
エミュレータ上に【残り続ける】のでそういう時は一度エミュレータ上のアプリを
削除することでマスタデータありのsqliteファイルがコピーされます

## 参考

[GRDB.swiftというSQLiteライブラリがイイ感じだった](https://qiita.com/owen/items/84fb05931946120523ed)
[★Swift 4 GRDB.swift(SQLite)を使ってみた](https://qiita.com/unpi/items/5ca166f280aeb732edd9) 
[GRDB.swiftの生SQL発行とマイグレーション](https://www.letitride.jp/entry/2019/12/16/103415)