MENU

【swift アプリ開発】Swift Sqliteを使ってみよう!

  • URLをコピーしました!
ios-appdevelopment-0014-03

こんにちは!Popoです。

こんな方へのお勧めの記事です。

  • 「Sqlite」を使ってみたい方

5年以上、スマフォ側でデータベースを使用する機会がなく、5年以上前の状態で止まったままになっていました。😓

スマフォ側で大量データを操作するようなアプリ開発を行ってこなかったため、「UserDefaults」で済ませてきた次第です。

「UserDefaults」のメリット、デミリットをまとめると、

メリットデメリット
扱いが簡単
永続的にデータを保存できる
アプリを削除するとデータが消えてしまう

セキュリティ面も暗号化して保管していました。

わざわざSqliteを使用するという機会がありませんでした

いい機会なので、「Sqliteを使ったサンプルを作成してみよう」と思いSqliteを使ってみる事にしました。

参考にさせていただいた記事になります。

目次

5年以上前のSqlite使用方法

5年以上前のSqlite使用方法

以前、Sqlite使用していたのは、Objective-cからSwiftへの移行時期で、Swiftでの開発を進めている頃でした。

そのためObjective-cのライブラリである「FMDB」を使用していました。

FMDBの設定方法の概要

  • 「General」タブ内の「Linked Frameworks and Libraries」から「libsalite3.0.dylib」の追加
  • CocoaPodsでFMDBをインストール
  • Header Fileを作成し下記をimport
    #import “FMDatabase.h”
    #import “FMResultSet.h”
    #import “FMDatabaseAdditions.h”
    #import “FMDatabaseQueue.h”
    #import “FMDatabasePool.h”
  • 「Build Setting 」→ 「Swift Compiler」 – 「Code Generation」 → 「Objective-C Bridging Header」に作成したヘッダーファイルを設定
  • Swift側のクラスで使用

なかなか面倒な設定ですね。

ところが現在では、import SQLite3」の記述だけです。😊

アプリの動作環境

アプリの動作環境

今回の開発環境です。

項目バージョン
XcodeVersion 14.3.1 (14E300c)
SwiftSwift version 5.8.1
MacOSmacOS Ventura バージョン13.4(22F66)

Sqliteの利用方法

Sqliteの利用方法

それでは、Sqliteの使用例を解説していきたいと思います。

ロジックパターンを覚えれば簡単です。👍

前提

フレームワークをimportします。

import UIKit
import SQLite3

データベース作成

はじめにデータベースを作成します。

ソースコード

Documentフォルダに「sample.db」というデータベースを作成します。

Documentフォルダのパスを生成し、「sqlite3_open」でデータベースをcreateします。


import UIKit
import SQLite3


class OneSqlite: NSObject {

    
    fileprivate var dbPointer: OpaquePointer?
    fileprivate let dbfile: String = "sample.db"
    
    /*
     * データベース作成
     */
    
    func createOneDB() -> Bool
    {
        
        let filePath = try! FileManager.default.url(
            for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
            .appendingPathComponent(self.dbfile)
        
        self.dbPointer = nil
        if sqlite3_open(filePath.path, &self.dbPointer) == SQLITE_OK {
 
            return true
        } else {
            print("Creating DB Error.")
            return false
        }
    }
}

上記クラスをCallします。


import UIKit

class OneViewController: UIViewController {

    fileprivate var oneSqlite : OneSqlite!
    
    override func viewDidLoad() {
        super.viewDidLoad()

        //sqliteデータベース作成
        self.oneSqlite = OneSqlite()
        if (!self.oneSqlite.createOneDB())
        {
            print("データベース作成失敗")
        }
    }

}

実行結果

実行後、データベースが作成されているか確認してみましょう。

Xcode「Windows」メニューの「Device and Simulators」を選択します。

Windows

下記の子画面が表示されます。

Device and Simulators

「Download Container…」を選択して、ファイルをダウンロードします。

その中身を確認!

データベース

作成されていますね。

テーブル作成

次は、テーブルを作成します。

ソースコード

  • OneSqlite

データベース登録時と同じクラス(OneSqlite)に定義しています。

「sqlite3_prepare_v2」でsqlステートメントをコンパイルして、「sqlite3_step」で実行します。


    /*
     * テーブル作成
     */
    func createOneTable() -> Bool
    {
        
        let createSql = """
                CREATE TABLE IF NOT EXISTS members (
                    member_id INTEGER NOT NULL PRIMARY KEY,
                    member_number TEXT NOT NULL,
                    first_name TEXT NULL,
                    last_name TEXT NULL,
                    age TEXT NULL
                );
                """
        
        var createTable : OpaquePointer? = nil
        if sqlite3_prepare_v2(self.dbPointer, createSql, -1, &createTable, nil) == SQLITE_OK {
            if sqlite3_step(createTable) == SQLITE_DONE {       
                return true
            } else {
                return false
            }
        } else {
            return false
        }
  • OneViewController

上記メソッドをCallします。データベース作成完了後、テーブル作成を行う流れにしています。


import UIKit

class OneViewController: UIViewController {

    fileprivate var oneSqlite : OneSqlite!
    
    override func viewDidLoad() {
        super.viewDidLoad()

        //sqliteデータベース作成
        self.oneSqlite = OneSqlite()
        if (self.oneSqlite.createOneDB())
        {
            if (self.oneSqlite.createOneTable())
            {
                print("テーブル作成成功")
            }
        }
    }
}

実行結果

テーブルが作成できています。

membersテーブル

データ登録

ソースコード

  • OneSqlite

同様に「sqlite3_prepare_v2」でsqlステートメントをコンパイルして、「sqlite3_bind_int」「sqlite3_bind_text」で登録値を設定します。

「sqlite3_step」でsqlを実行します。

    /*
     * データ登録
     */
    func insertOneTable() -> Bool {
        let insertSql = """
                        INSERT INTO members
                            (member_id, member_number, first_name, last_name, age)
                            VALUES
                            (?, ?, ?, ?, ?);
                        """;
        var insertStmt: OpaquePointer? = nil
        
        if sqlite3_prepare_v2(self.dbPointer, (insertSql as NSString).utf8String, -1, &insertStmt, nil) != SQLITE_OK {
            print("sqlite3_prepare_v2 Error")
            return false
        }
        
        sqlite3_bind_int(insertStmt, 1,0)
        sqlite3_bind_text(insertStmt, 2, ("001" as NSString).utf8String, -1, nil)
        sqlite3_bind_text(insertStmt, 3, ("Tanaka" as NSString).utf8String, -1, nil)
        sqlite3_bind_text(insertStmt, 4, ("Satoshi" as NSString).utf8String, -1, nil)
        sqlite3_bind_text(insertStmt, 5, ("35" as NSString).utf8String, -1, nil)
        
        if sqlite3_step(insertStmt) != SQLITE_DONE {
            print("sqlite3_step Error")
            sqlite3_finalize(insertStmt)
            return false
        }
        sqlite3_finalize(insertStmt)
        return true
    }
  • OneViewController

データベース作成、テーブル作成正常終了後にデータ登録を実行しています。


import UIKit

class OneViewController: UIViewController {

    fileprivate var oneSqlite : OneSqlite!
    
    override func viewDidLoad() {
        super.viewDidLoad()

        //sqliteデータベース作成
        self.oneSqlite = OneSqlite()
        if (self.oneSqlite.createOneDB())
        {
            if (self.oneSqlite.createOneTable())
            {
                if (self.oneSqlite.insertOneTable())
                {
                    print("データ作成成功")
                }
            }
        }
    }

}

実行結果

データが作成されています。

データ登録

データ更新

ソースコード

  • OneSqlite

「sqlite3_prepare_v2」→「sqlite3_bind_int」「sqlite3_bind_text」→「sqlite3_step」と処理の流れは、データ登録と同じです。

     /*
     * データ更新
     */
    func updateOneTable() -> Bool {
        let updateSql = """
        UPDATE  members
        SET     member_number = ?,
                first_name = ?,
                last_name = ?,
                age = ?
        WHERE   member_id = ?
        """
        var updateStmt: OpaquePointer? = nil
        
        if sqlite3_prepare_v2(self.dbPointer, (updateSql as NSString).utf8String, -1, &updateStmt, nil) != SQLITE_OK {
            print("sqlite3_prepare_v2 Error")
            return false
        }
        
        sqlite3_bind_text(updateStmt, 1, ("002" as NSString).utf8String, -1, nil)
        sqlite3_bind_text(updateStmt, 2, ("Itou" as NSString).utf8String, -1, nil)
        sqlite3_bind_text(updateStmt, 3, ("Hanako" as NSString).utf8String, -1, nil)
        sqlite3_bind_text(updateStmt, 4, ("40" as NSString).utf8String, -1, nil)
        sqlite3_bind_int(updateStmt, 5, 1)

        if sqlite3_step(updateStmt) != SQLITE_DONE {
            print("sqlite3_step Error")
            sqlite3_finalize(updateStmt)
            return false
        }
        sqlite3_finalize(updateStmt)
        return true
    }
  • OneViewController

データ登録メソッド正常終了後、Callしてやります。


import UIKit

class OneViewController: UIViewController {

    fileprivate var oneSqlite : OneSqlite!
    
    override func viewDidLoad() {
        super.viewDidLoad()

        //sqliteデータベース作成
        self.oneSqlite = OneSqlite()
        if (self.oneSqlite.createOneDB())
        {
            if (self.oneSqlite.createOneTable())
            {
                if (self.oneSqlite.insertOneTable())
                {
                    if (self.oneSqlite.updateOneTable())
                    {
                        print("データ更新成功")
                    }
                }
            }
        }
    }
}

実行結果

データを更新できました。

データ更新1

データ登録時

データ更新2

データ更新後

データ削除

ソースコード

  • OneSqlite

削除も同様です。

    /*
     * データ削除
     */
    func deleteOneTable() -> Bool {
        let deleteSql = "DELETE FROM members WHERE member_id = ?;";
        var deleteStmt: OpaquePointer? = nil
        
        if sqlite3_prepare_v2(self.dbPointer, (deleteSql as NSString).utf8String, -1, &deleteStmt, nil) != SQLITE_OK {
            print("sqlite3_prepare_v2 Error")
            return false
        }
        
        sqlite3_bind_int(deleteStmt, 1, 0)
        
        if sqlite3_step(deleteStmt) != SQLITE_DONE {
            print("sqlite3_step Error")
            sqlite3_finalize(deleteStmt)
            return false
        }

        sqlite3_finalize(deleteStmt)
        return true
    }
  • OneViewController

データ更新メソッド正常終了後、Callしてやります。


import UIKit

class OneViewController: UIViewController {

    fileprivate var oneSqlite : OneSqlite!
    
    override func viewDidLoad() {
        super.viewDidLoad()

        //sqliteデータベース作成
        self.oneSqlite = OneSqlite()
        if (self.oneSqlite.createOneDB())
        {
            if (self.oneSqlite.createOneTable())
            {
                if (self.oneSqlite.insertOneTable())
                {
                    
                    if (self.oneSqlite.updateOneTable())
                    {
                        if (self.oneSqlite.deleteOneTable())
                        {
                            print("データ削除成功")
                        }
                    }
                }
            }
        }
    }
}

実行結果

データは削除されています。

データ削除

データ検索

ソースコード

  • OneSqlite

検索結果、エラーメッセージ、検索値を引き継ぐようにしてみました。

    /*
     * データ削除
     */
    func getMember() -> (success: Bool, errorMessage: String?,setMember:OneViewController.memberStruct?) {
     
        var saveMember: OneViewController.memberStruct? = nil
        
        let sql = """
            SELECT  member_id, member_number, first_name, last_name, age
            FROM    members
            WHERE   member_id = ?;
            """
        
        var stmt: OpaquePointer? = nil
        if sqlite3_prepare_v2(self.dbPointer, (sql as NSString).utf8String, -1, &stmt, nil) != SQLITE_OK {
            return (false, "sqlite3_prepare_v2 Error",saveMember)
        }
        
        sqlite3_bind_int(stmt, 1, 0)
        
        if sqlite3_step(stmt) == SQLITE_ROW {
            let memberId:Int = Int(sqlite3_column_int(stmt, 0))
            let memberNumber:String = String(describing: String(cString: sqlite3_column_text(stmt, 1)))
            let firstName:String = String(describing: String(cString: sqlite3_column_text(stmt, 2)))
            let lastName:String = String(describing: String(cString: sqlite3_column_text(stmt, 3)))
            let age:String = String(describing: String(cString: sqlite3_column_text(stmt, 4)))

            saveMember = OneViewController.memberStruct(member_Id: memberId, member_Number: memberNumber, first_Name: firstName, last_Name: lastName, Age: age)
         } else {
            return (false, "検索エラー",saveMember)
        }
        
        sqlite3_finalize(stmt)
        return (true, "", saveMember)
    }
  • OneViewController

今回は構造体を追加して、取得した値を引き継いでみました。

    //画像格納構造体
    struct memberStruct {
        var member_Id: Int
        var member_Number: String
        var first_Name: String
        var last_Name: String
        var Age: String
    }

検索結果を判断して、検索値、エラーメッセージの表示を分けています。


import UIKit

class OneViewController: UIViewController {

    fileprivate var oneSqlite : OneSqlite!
    //画像格納構造体
    struct memberStruct {
        var member_Id: Int
        var member_Number: String
        var first_Name: String
        var last_Name: String
        var Age: String
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()

        //sqliteデータベース作成
        self.oneSqlite = OneSqlite()
        if (self.oneSqlite.createOneDB())
        {
            if (self.oneSqlite.createOneTable())
            {
                if (self.oneSqlite.insertOneTable())
                {
                    
                    if (self.oneSqlite.updateOneTable())
                    {
                        /*
                        if (self.oneSqlite.deleteOneTable())
                        {
                            print("データ削除成功")
                        }
                         */
                        let (success, errorMessage, memberStruct) = self.oneSqlite.getMember()
                        if success
                        {
                            print("memberStruct----",memberStruct ?? memberStruct as Any)
                        } else {
                            print("errorMessage----",errorMessage ?? "")
                        }

                    }
                }
            }
        }
    }
}

実行結果

検索成功時

データ検索

検索エラー時

データ検索エラー

まとめ

まとめ

フレームワークをimportするだけで簡単にSqliteが使用できることがわかりました。

objective-cのライブラリ「FMDB」を使わなくて済みます。

5年以上もスキルが止まっていたなんて!
悲しい〜😱

データ量が少し多い場合も、NSArray、NSMurableArrayなどを「UserDefaults」に保存して使用していました。

こんなに手軽にSqliteが使用できるのであれば、今後は積極的にSqliteを使用していきたいと思っています。

しかし、重要なデータや大量データはサーバーサイドで保管することが一般的なので、「UserDefaults」で済ませてしまうことが多いと思っています。

大昔に使ったきり、使っていないような機能がないかちょっと調べてみたいと思います。😅

それではまた!

よかったらシェアしてね!
  • URLをコピーしました!
目次