Swift搭配Sqlite資料庫的使用
作者:楊先民
精誠資訊/恆逸教育訓練中心資深講師
※網路引用請註明完整出處
四年前曾經使用 Objective-C寫過 iphone程式,並且還上架了一個油耗管理的程式,時至今天四年後了,又再自學了新的 iphone程式開發,這次是使用新的開發語言 Swift,同樣的也是要連到資料庫,就看該怎麼撰寫相關的程式吧。
使用 SQLITE資料庫
SQLite資料庫是目前公認在撰寫行動裝置中最有效的資料庫,它是一個用 C++寫出來的小型資料庫,但是速度相當的快速,能夠支援 ANSI指令,常被用來儲存行動裝置的一些大量資料,不但如此,有些桌上型的專案如果需要存放資料庫的話,也有可能採用 SQLite當作它們的首選,可見其效能與安定性。
這次我所使用的
SQLite管理工具,是之前特價時買的,現在再到 Apple store看了一下這個軟體:
哇塞,當初有賺到的概念,現在要快5000元!
不過您可以到 Apple
Store上搜尋 SQLite關鍵字,會出現一些同樣是
SQLite的管理工具,您可以下載把您的第一個資料庫建立起來。
每次撰寫 iphone程式都是有特別目的,四年前是為了要學 iphone 程式開發所以學習如何撰寫,而這次是為了要寫一個很厲害的程式,這個程式已經上架了,大概是世界第一支吧,利用 iphone計算自行車功率的程式。(程式請搜尋 apple store:BikeSpeeding)
隨著科學訓練的普及,選手不應該再盲目的訓練,而是要將目標擺在「功率訓練」上,我這支程式就是用來利用功率的方式,估算爬坡時所需的功率,並且還可以自行配速產生現在網路上當紅的 Zwift課表。
如果以上的名詞您都沒聽懂,是的,其實您已經在這個世界上落伍了,不過這不是重點,本篇文章主要是介紹 iphone開發與 SQLite資料。
首先利用管理工具把資料表建立起來,這次我的專案會需要下列的資料表:
建資料表的方式不多談,畢竟如果您有一點資料表建立的基礎,這個都不難。
我們會記錄 Road,也就是山路爬坡資訊,目前的資料如下:
而山路也有分級,這樣才可以在 iphone看到以下的效果:
利用 pickerview的方式,先選擇坡級,再選擇您要爬的山路。
好吧,這個都是從資料庫中抓出來的(只想表達這點),那麼就來看這個程式抓取資料庫的部分該怎麼做吧!
由於我們今天的主題是使用
Swift存取 SQLite資料庫,所以都會用
Swift來做,但是我們如果想要使用
SQLite,必須要加入標頭檔,因為我四年前寫 SQLite的時候它是3.0版,到了四年後…它還是3.0,根本沒變,可想而知它沒有提供對 Swift的支援,所以我們要利用橋接的方式把 Swift與 Objective-C橋接起來。
幸好這點 apple做的還不錯,不然真的寫程式會混亂,不過您需要先在 XCode建立一個橋接檔,也就是需要建立一個 Header file(我命名為 BridgingHeader.h),如下圖:
然後在這個 header檔中,只要單純的撰寫下面的程式:
#include <sqlite3.h>
然後存檔…
然後開啟專案設定,選擇 Targets的專案名稱,切換到 Build Settings,將這個 header檔加進來,就可以完成和 Object-C的連結。
接下來,加入 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/

0 意見:
張貼留言