iOS
 Computer >> コンピューター >  >> プログラミング >> iOS

iPhoneアプリでSQLiteデータベースにアクセスする方法をSwiftで解説

はじめに:データ保存はアプリ開発の重要要素

アプリケーションを設計するうえで、データの保存は最も重要な要素の一つです。データを保存する方法は数多くありますが、その中でも広く使われているのがSQLiteデータベースです。

iPhone上でSQLiteデータベースへアクセスする方法は複数ありますが、本記事ではSwiftを使った最もシンプルな方法を紹介します。

なお、SQLiteとはC言語のライブラリとして実装されたリレーショナルデータベース管理システム(RDBMS)であり、アプリケーションに組み込んで動作させる軽量データベースです。サーバーが不要で、モバイルアプリのローカルデータ保存に最適です。

このチュートリアルで作るもの

今回は、名前を入力するテキストフィールドを備えたサンプルアプリを作成します。「挿入」ボタンをタップすると入力した名前がSQLiteデータベースに保存され、「表示」ボタンをタップすると保存済みのデータが出力されます。

それでは始めましょう。

ステップ1:Xcodeプロジェクトの作成

Xcodeを開き、「Single View Application」を選択して、プロジェクト名を「DBSqlite」とします。

ステップ2:UIの構築

Main.storyboardを開き、テキストフィールドを1つとボタンを2つ配置します。ボタンは「挿入(Insert)」と「表示(Show Data)」用の2つです。

iPhoneアプリでSQLiteデータベースにアクセスする方法をSwiftで解説

ステップ3:IBActionとIBOutletの接続

ボタン2つには@IBActionを、テキストフィールドには@IBOutletを作成し、それぞれ「btnInsert」「btnShowData」「name」という名前を付けます。

これで、データを挿入するためのボタンと、データを表示するためのボタン、そしてデータベースに登録する名前を入力するテキストフィールドが準備できました。

ステップ4:SQLiteファイルの作成とデータベース接続

次に、SQLiteファイルを作成し、データベースへの接続を開きます。

ViewController.swiftの先頭で、以下のようにSQLite3をインポートします。

import SQLite3

ViewDidLoadの下に以下のコードを記述すると、.sqliteファイルが作成され、その保存場所を出力できます。ここでは名前のみを保存するため、ファイル名は「user_name.sqlite」としています。

let file_URL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false).appendingPathComponent("user_name.sqlite")

続いて、sqlite3_open()関数を使ってデータベースを開きます。操作に使用するOpaquePointer型のオブジェクトを作成しましょう。この変数はViewDidLoadより上のグローバルな位置に宣言します。

var db: OpaquePointer?

ステップ5:テーブルの作成

次にテーブルを作成します。viewDidLoadメソッド内に以下のコードを記述してください。

//creating table
if sqlite3_exec(db, "CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT)", nil, nil, nil) != SQLITE_OK {
    let errorMsg = String(cString: sqlite3_errmsg(db)!)
    print("There's error creating the table: \(errorMsg)")
}

このSQL文では、自動増分される主キー「id」と、テキスト型の「name」カラムを持つusersテーブルを、存在しない場合のみ作成しています。

ステップ5完了時点でのコード全体

import UIKit
import SQLite3
class ViewController: UIViewController {
    var db: OpaquePointer?
    @IBOutlet var name: UITextField!
    override func viewDidLoad() {
        super.viewDidLoad()
        let file_URL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
.appendingPathComponent("user_name.sqlite")
        print (file_url) //to print the path of sqlite.
        //opening the database
        if sqlite3_open(file_URL.path, &db) != SQLITE_OK {
            print("There's error in opening the database")
        }
        //create table
        if sqlite3_exec(db, "CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT)", nil, nil, nil) != SQLITE_OK {
            let errorMsg = String(cString: sqlite3_errmsg(db)!)
            print("There's error creating the table: \(errorMsg)")
        }
    }
    @IBAction func btnInsert(_ sender: Any) {
    }
    @IBAction func btnShowData(_ sender: Any) {
    }
}

上記のコードを実行してエラーが発生しなければ成功です。指定した場所に移動して、sqliteファイルが生成されていることを確認してみてください。

ステップ6:データの挿入処理

次に、データを挿入するコードを書きます。btnInsertに以下のコードを記述してください。

var statement: OpaquePointer?
guard let user_name = name.text, !user_name.isEmpty else {
    return
}
let query = "INSERT INTO users (name) VALUES (?)"
if sqlite3_prepare(db, query, -1, &statement, nil) != SQLITE_OK {
    let errmsg = String(cString: sqlite3_errmsg(db)!)
    print("error preparing insert: \(errmsg)")
    return
}
if sqlite3_bind_text(statement, 1, user_name, -1, nil) != SQLITE_OK {
    let errmsg = String(cString: sqlite3_errmsg(db)!)
    print("failure binding name: \(errmsg)")
    return
}
if sqlite3_step(statement) != SQLITE_DONE {
    let errmsg = String(cString: sqlite3_errmsg(db)!)
    print("failure inserting users: \(errmsg)")
return

ここでは、テキストフィールドに入力された値を単純にテーブルへ書き込んでいます。「?」プレースホルダーとsqlite3_bind_text()を使用することで、SQLインジェクションを防ぎながら値を安全にバインドできる点もポイントです。

ステップ7:データの表示処理

次に、保存したデータを表示します。btnShowDataに以下のコードを記述してください。

let query = "SELECT * FROM users"
var statement:OpaquePointer?
if sqlite3_prepare(db, query, -1, &statement, nil) != SQLITE_OK {
    let errmsg = String(cString: sqlite3_errmsg(db)!)
    print("error preparing insert: \(errmsg)")
    return
}
while(sqlite3_step(statement) == SQLITE_ROW) {
    let name = String(cString: sqlite3_column_text(statement, 1))
    print(name)
}

sqlite3_step()が行を返す限りループを続け、各レコードからnameカラムの値を取り出して出力します。

完成版のコード全体

import UIKit
import SQLite3
class ViewController: UIViewController {
    var db: OpaquePointer?
    @IBOutlet var name: UITextField!
    override func viewDidLoad() {
        super.viewDidLoad()
        let file_URL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
        .appendingPathComponent("user_name.sqlite")
        //opening the database
        if sqlite3_open(file_URL.path, &db) != SQLITE_OK {
            print("There's error in opening the database")
        }
        //creating table
        if sqlite3_exec(db, "CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT)", nil, nil, nil) != SQLITE_OK {
            let errorMsg = String(cString: sqlite3_errmsg(db)!)
            print("There's error creating the table: \(errorMsg)")
        }
    }
    @IBAction func btnInsert(_ sender: Any) {
        var statement: OpaquePointer?
        guard let user_name = name.text, !user_name.isEmpty else {
            return
        }
        let query = "INSERT INTO users (name) VALUES (?)"
        if sqlite3_prepare(db, query, -1, &statement, nil) != SQLITE_OK {
            let errmsg = String(cString: sqlite3_errmsg(db)!)
            print("error preparing insert: \(errmsg)")
            return
        }
        if sqlite3_bind_text(statement, 1, user_name, -1, nil) != SQLITE_OK {
            let errmsg = String(cString: sqlite3_errmsg(db)!)
            print("failure binding name: \(errmsg)")
            return
        }
        if sqlite3_step(statement) != SQLITE_DONE {
            let errmsg = String(cString: sqlite3_errmsg(db)!)
            print("failure inserting users: \(errmsg)")
            return
        }
    }
    @IBAction func btnShowData(_ sender: Any) {
        let query = "SELECT * FROM users"
        var statement:OpaquePointer?
        if sqlite3_prepare(db, query, -1, &statement, nil) != SQLITE_OK {
            let errmsg = String(cString: sqlite3_errmsg(db)!)
            print("error preparing insert: \(errmsg)")
            return
        }
        while(sqlite3_step(statement) == SQLITE_ROW) {
            let name = String(cString: sqlite3_column_text(statement, 1))
            print(name)
        }
    }
}

動作確認

コードを実行し、テキストフィールドに「HELLO」と入力して挿入ボタンをタップします。続いて表示ボタンをタップすると、Xcodeのデバッガーエリアの出力欄に「HELLO」が表示されるはずです。

iPhoneアプリでSQLiteデータベースにアクセスする方法をSwiftで解説iPhoneアプリでSQLiteデータベースにアクセスする方法をSwiftで解説

まとめ

本記事では、SwiftとSQLite3ライブラリを使って、iPhoneアプリ内でローカルデータベースを扱う基本手順を解説しました。データベースファイルの作成・接続、テーブル定義、プレースホルダーを使った安全なデータ挿入、SELECT文によるデータ取得という一連の流れを押さえておけば、実際のアプリ開発でも応用できます。さらに発展させたい場合は、UPDATEやDELETE処理の追加や、結果をUI(UITableViewなど)に反映させる実装にも挑戦してみてください。

  1. iPhoneでフォトアルバムの名前を変更する方法【初心者向け解説】

    iPhoneに写真やアルバムがたくさん溜まってくると、以前付けたアルバムの名前が分かりにくくなることがあります。アルバムを作成する際には必ず名前の入力を求められますが、うっかり間違った名前を付けてしまい、後から修正したいというケースも少なくありません。 あわせて読みたい:iPhoneのバッテリー寿命を改善するためのヒントとコツ まず知っておきたい注意点 手順の説明に入る前に、押さえておきたいポイントがあります。「カメラロール」「スクリーンショット」「人」「最近削除した項目」「ライブフォト」「マイフォトストリーム」「アニメーション」「セルフィー」「ビデオ」「場所」など、iOSが自動的に生成する標

  2. iPhoneでBluetooth名を変更する方法|本体・接続デバイス別に解説

    すべてのスマートフォンには、メーカーによってBluetooth機能が標準搭載されています。Appleは自社デバイス間のデータ転送にBluetoothを使用していませんが、それでもBluetoothはあらゆるスマートフォンに欠かせない重要な機能です。Bluetoothは、スピーカーやスマートTVなどの別デバイスへの音声・動画・写真のストリーミングにも活用できます。さらに、Apple Watch、AirPods、スマート体重計のように、親デバイスとの接続にBluetoothを必要とするガジェットも数多く存在します。 iPhoneに複数のデバイスが接続されていると、どれがどのデバイスなのか識別する