0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

SwiftでFMDB入門 〜 SQLiteを安全に扱うための第一歩 〜

Posted at

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/

もし周りに、
移動でお困りの方や介護タクシーを探している方がいらっしゃいましたら、
ご紹介いただけますと幸いです。

今後も、実務で詰まりやすい技術トピックを中心に発信していきます。
最後までお読みいただき、ありがとうございました。

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?