こんにちは!Popoです。
こんな方へのお勧めの記事です。
- 「Sqlite」を使ってみたい方
5年以上、スマフォ側でデータベースを使用する機会がなく、5年以上前の状態で止まったままになっていました。😓
スマフォ側で大量データを操作するようなアプリ開発を行ってこなかったため、「UserDefaults」で済ませてきた次第です。
「UserDefaults」のメリット、デミリットをまとめると、
メリット | デメリット |
---|---|
扱いが簡単 永続的にデータを保存できる | アプリを削除するとデータが消えてしまう |
セキュリティ面も暗号化して保管していました。
わざわざSqliteを使用するという機会がありませんでした
いい機会なので、「Sqliteを使ったサンプルを作成してみよう」と思い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」の記述だけです。😊
アプリの動作環境
今回の開発環境です。
項目 | バージョン |
Xcode | Version 14.3.1 (14E300c) |
Swift | Swift version 5.8.1 |
MacOS | macOS Ventura バージョン13.4(22F66) |
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」を選択します。
下記の子画面が表示されます。
「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("テーブル作成成功")
}
}
}
}
実行結果
テーブルが作成できています。
データ登録
ソースコード
- 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("データ更新成功")
}
}
}
}
}
}
実行結果
データを更新できました。
データ登録時
データ更新後
データ削除
ソースコード
- 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 ?? "")
}
}
}
}
}
}
}
実行結果
検索成功時
検索エラー時
まとめ
objective-cのライブラリ「FMDB」を使わなくて済みます。
5年以上もスキルが止まっていたなんて!
悲しい〜😱
データ量が少し多い場合も、NSArray、NSMurableArrayなどを「UserDefaults」に保存して使用していました。
こんなに手軽にSqliteが使用できるのであれば、今後は積極的にSqliteを使用していきたいと思っています。
しかし、重要なデータや大量データはサーバーサイドで保管することが一般的なので、「UserDefaults」で済ませてしまうことが多いと思っています。
大昔に使ったきり、使っていないような機能がないかちょっと調べてみたいと思います。😅
それではまた!