1. 背景
フリーランスエンジニアの Rio です。
これまで
会社員 → フリーランス → 経営者 → フリーランス(兼 経営者)
という少し変わったキャリアを歩んできました。
現在はフリーランスエンジニアとしてコーディング業務に携わりつつ、
スタートアップの経営も行っています。
そんな中、ひょんなことから参画したプロダクトで
モバイルDBをがっつり扱う必要がある案件に関わることになりました。
iOSアプリで Swift + SQLite を使うにあたり、
生SQLiteを直接扱うのではなく、
ラッパーライブラリである FMDB を使うことにしました。
そこで本記事では、
SwiftでFMDBを使い始めるための入門知識を整理していきます。
2. 解説
FMDBとは?
FMDB は、SQLiteを Objective-C / Swift から安全に扱うためのラッパーライブラリ です。
- SQLiteのSQLをそのまま書ける
- 低レベルなC APIを意識しなくてよい
-
プレースホルダ(
?)による安全なバインドが可能 - iOS開発では長年使われている実績がある
SwiftでSQLiteを使う際の、定番ライブラリの一つです。
FMDBで覚えるべき基本クラス
FMDBでは、まず以下の3つを押さえればOKです。
| 役割 | クラス |
|---|---|
| DB接続 | FMDatabase |
| クエリ結果 | FMResultSet |
| スレッド安全 | FMDatabaseQueue |
Swiftでは FMDatabaseQueue を使うのがほぼ必須 です。
SQLiteは同時アクセスに弱いため、Queueで直列化します。
データベースを開く
let dbPath = FileManager.default
.urls(for: .documentDirectory, in: .userDomainMask)[0]
.appendingPathComponent("sample.db")
.path
let dbQueue = FMDatabaseQueue(path: dbPath)
これでSQLiteファイルへの接続準備が完了です。
テーブル作成(executeUpdate)
dbQueue?.inDatabase { db in
let sql = """
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY,
name TEXT,
age INTEGER
)
"""
db.executeUpdate(sql, withArgumentsIn: [])
}
INSERT(? プレースホルダ)
let insertSQL = """
INSERT INTO users (name, age)
VALUES (?, ?)
"""
dbQueue?.inDatabase { db in
db.executeUpdate(insertSQL, withArgumentsIn: [
"Taro",
25
])
}
ポイント
• ? の数と配列の順番が一致している必要がある
• 自動でエスケープされる
• SQLインジェクション対策になる
❌ NG例:
"INSERT INTO users VALUES ('\(name)', \(age))"
SELECT(executeQuery)
let selectSQL = """
SELECT id, name, age
FROM users
WHERE age >= ?
"""
dbQueue?.inDatabase { db in
let rs = try! db.executeQuery(selectSQL, values: [20])
while rs.next() {
let id = rs.int(forColumn: "id")
let name = rs.string(forColumn: "name")!
let age = rs.int(forColumn: "age")
print(id, name, age)
}
}
- executeQuery はSELECT専用
- FMResultSet を while rs.next() で走査する
?(プレースホルダ)の考え方
WHERE age >= ?
values: [20]
- SQLは 構造だけを定義
- 値は 後から安全にバインド
- テーブル名やカラム名には使えない
FMDBを使う最大のメリットの一つが、この安全なバインドです。
トランザクション(実務では必須)
dbQueue?.inTransaction { db, rollback in
let ok1 = db.executeUpdate(
"UPDATE users SET age = ? WHERE id = ?",
withArgumentsIn: [30, 1]
)
let ok2 = db.executeUpdate(
"UPDATE users SET age = ? WHERE id = ?",
withArgumentsIn: [40, 2]
)
if !ok1 || !ok2 {
rollback.pointee = true
}
}
途中で失敗した場合、すべてロールバックされます。
FMDBでよくある注意点
- FMDatabase を直接使わない(スレッド事故)
- ? の数と引数の数を一致させる
- 文字列連結でSQLを書かない
- ResultSetの扱いに注意する
3. 結び
私が起業している会社では、
「高齢者・ハンディキャップのある方々が気軽に移動できる世界」
を実現すべく、
車椅子のまま乗り込めるタクシー(介護タクシー・福祉タクシー)専用の配車アプリ
を開発・運営しています🚕👩🦽📲
▼ サービスページ
https://textify-image-page.lovable.app/
もし周りに、
移動でお困りの方や介護タクシーを探している方がいらっしゃいましたら、
ご紹介いただけますと幸いです。
今後も、実務で詰まりやすい技術トピックを中心に発信していきます。
最後までお読みいただき、ありがとうございました。