Swift搭配 Sqlite資料庫的使用

by adonisy 5. 三月 2018 16:06

作    者:楊先民
審    稿:張智凱


1    前言

 


四年前曾經使用 Objective-C寫過 iphone程式,並且還上架了一個油耗管理的程式,時至今天四年後了,又再自學了新的 iphone程式開發,這次是使用新的開發語言 Swift,同樣的也是要連到資料庫,就看該怎麼撰寫相關的程式吧。

2    使用 Sqlite資料庫

 

SQLite資料庫是目前公認在撰寫行動裝置中最有效的資料庫,它是一個用 C++寫出來的小型資料庫,但是速度相當的快速,能夠支援 ANSI指令,常被用來儲存行動裝置的一些大量資料,不但如此,有些桌上型的專案如果需要存放資料庫的話,也有可能採用 SQLite當作它們的首選,可見其效能與安定性。

這次我所使用的 SQLite管理工具,是之前特價時買的,現在再到 Apple store看了一下這個軟體:

image

哇塞,當初有賺到的概念,現在要快5000元!

不過你可以到 Apple Store上搜尋 SQLite關鍵字,會出現一些同樣是 SQLite的管理工具,你可以下載把你的第一個資料庫建立起來。

每次撰寫 iphone程式都是有特別目的,四年前是為了要學 iphone 程式開發所以學習如何撰寫,而這次是為了要寫一個很厲害的程式,這個程式已經上架了,大概是世界第一支吧,利用 iphone計算自行車功率的程式。(程式請搜尋 apple store:BikeSpeeding)

隨著科學訓練的普及,選手不應該再盲目的訓練,而是要將目標擺在「功率訓練」上,我這支程式就是用來利用功率的方式,估算爬坡時所需的功率,並且還可以自行配速產生現在網路上當紅的 Zwift課表。

如果以上的名詞你都沒聽懂,是的,其實你已經在這個世界上落伍了,不過這不是重點,本篇文章主要是介紹 iphone開發與 SQLite資料。

首先利用管理工具把資料表建立起來,這次我的專案會需要下列的資料表:

image

建資料表的方式不多談,畢竟如果你有一點資料表建立的基礎,這個都不難。

我們會記錄 Road,也就是山路爬坡資訊,目前的資料如下:

image

而山路也有分級,這樣才可以在 iphone看到以下的效果:

image

利用 pickerview的方式,先選擇坡級,再選擇你要爬的山路。

好吧,這個都是從資料庫中抓出來的(只想表達這點),那麼就來看這個程式抓取資料庫的部分該怎麼做吧!

由於我們今天的主題是使用 Swift存取 SQLite資料庫,所以都會用 Swift來做,但是我們如果想要使用 SQLite,必需要加入標頭檔,因為我四年前寫 SQLite的時後它是 3.0版,到了四年後…它還是3.0,根本沒變,可想而知它沒有提供對 Swift的支援,所以我們要利用橋接的方式把 Swift與 Objective-C橋接起來。

幸好這點 apple做的還不錯,不然真的寫程式會混亂,不過你需要先在 XCode建立一個橋接檔,也就是需要建立一個 Header file(我命名為 BridgingHeader.h),如下圖:

image

然後在這個 header檔中,只要單純的撰寫下面的程式:
#include <sqlite3.h>

然後存檔…
然後開啟專案設定,選擇 Targets的專案名稱,切換到 Build Settings,將這個 header檔加進來,就可以完成和 Object-C的聯結。

image

接下來,加入 SQLite程式庫,切換到 Build Phases,點選 Link Binary With Libraries(0 items),將 libsqlite3.tbd加進來。
附註:這個檔案是新的,之前的名稱叫 libsqlite3.dylib,當初我也曾經有所疑惑,不過現在確實是找不到 libsqlite3.dylib這個檔案了,所以就放心加進來吧!

好的,接下來就可以開始撰寫存取資料庫的程式了:

首先要宣告變數來儲存 SQLite資料庫,這個資料型別必需是 COpaquePointer,如下:

var db:COpaquePointer = nil //資料庫

接下來就可以利用 sqlite3_open的函數對資料庫連線,並且開啟資料庫,它的語法是這樣子的:

sqlite3_open(資料庫路徑,&資料庫變數)

雖然說在 Swift中已經把指標拿掉了,但是現在看起來,好像還是沒有拿掉嘛…
似乎還是得用 &的方式使用資料庫

如果開啟成功,則會傳回 SQLite_OK,用來判斷是否有這個資料庫檔案。

這個資料庫檔案我們會需要從 Documents目錄中取得,如果沒有這個檔案,需要從 mainBundle中將檔案複製到 Documents中,所以程式整體就會看起來如下:

let fm:NSFileManager = NSFileManager()
let src:String = NSBundle.mainBundle().pathForResource("BMountain", ofType: "sqlite")!
let dst:String = NSHomeDirectory()+"/Documents/BMountain.sqlite"

        if !fm.fileExistsAtPath(dst) {
            do {
                try fm.copyItemAtPath(src, toPath: dst)
            } catch _ {
            }
        }
        if sqlite3_open(dst, &db) != SQLITE_OK
        {
            print("無法開啟資料庫!")
            ////exit(1)
        }

特別注意是,Swift 2.0之後 copyItemAtPath,需要搭配 try catch的句法,不然程式可是不會編譯成功的!

完成後,需要利用sqlite3_prepare_v2這個指令準備執行預先寫好的 sql指令。

你可能會對資料查詢,就會有結果集傳回,需要接收,如果資料有很多結果集,有需要撰寫迴圈,如果是修改,則只要確定指令有無順利執行成功即可。

指令大概是長這樣子的
        sqlite3_prepare_v2(資料庫, sql變數, -1, 資料記錄變數, nil)
其中資料庫我們剛才有定義,sql變數則是需要轉成 UTF8String,而-1是最大讀取數,-1代表沒有限制,nil則是固定寫法。
所以程式就變成要這麼寫:
var statement:COpaquePointer=nil //資料記錄
var sql:NSString = "" //SQL指令
sql="update RoadDetail set FtpPercent = " + String(ftppercent) + " where RoadID = " + mountainid + " and RoidSec = " + mountain_sec
statement = nil
sqlite3_prepare_v2(db, sql.UTF8String, -1, &statement, nil)
        sqlite3_step(statement)
        sqlite3_finalize(statement)

這裡的示範是 update資料,所以 sqlite3_step執行不用判斷回傳結果,就是執行就好,最後再利用sqlite3_finalize(statement)指令將連線關閉。

如果預期會傳回結果集,如果只有一筆的話就這麼寫:

if sqlite3_step(statement) == SQLITE_ROW {
}

如果是有多筆結果的話就是用 while迴圈:

while sqlite3_step(statement) == SQLITE_ROW{

}
然後再利用 sqlite3_column_資料型別(資料記錄變數,索引值)將資料回傳到事先設定的變數中;其中只有處理字串比較麻煩,大概要這樣寫:

let tempstring = sqlite3_column_text(statement, 0)
let mountain_sec = String.fromCString(UnsafePointer<CChar>(tempstring))

其中欄位索引值0代表 select列表中的第一個欄位,第二個欄位索引值是1,依此類推。
若是 double,則是
sqlite3_column_double(statement, 1)
若是變數設定成 Float的話,則要把程式改成:
Float(sqlite3_column_double(statement, 1))
利用 Float函數轉型成 Float資料型別。

好啦,剩下的應該各位程式設計師可以搞定了,這期的資料庫先介紹到這邊,改天再來介紹我撰寫的新 iphone程式有多麼強大,這個 iphone 程式的下載地點在:


https://sites.google.com/site/bikespeeding/

Tags:

SQLite | 楊先民Adonis Young

不允許評論

NET Magazine國際中文電子雜誌

NET Magazine國際中文電子版雜誌,由恆逸資訊創立於2000,自發刊日起迄今已發行超過500篇.NET相關技術文章,擁有超過40000名註冊讀者群。NET Magazine國際中文電子版雜誌希望藉於電子雜誌與NET Developer達到共同學習與技術新知分享,歡迎每一位對.NET 技術有興趣的朋友們多多支持本雜誌,讓作者群們可以有持續性的動力繼續爬文。<請加入免費訂閱>

月分類Month List