在開發Event Page的程式部分之前,需要先把資料方面的東西準備好,這樣才可以更實際的測試~之前寫過的app是有Server後台的,所以都是用API的方式去要資料,相關的邏輯居多不處理,這次換的寫法,在local端建立資料庫,把使用者的資料自己存在自己的手機中,但儲存資料的方式很多種(明天的議題會分享常見的五種),這邊我選擇使用 SQLite 做大部分的資料儲存
早期在Swift要使用SQLite挺麻煩的,還要架什麼Brige去連接,光聽就暈了,還好現在有神人提供好用的第三方元件庫,SQLite.swift,一開始建立專案的時候,我們也用Cocoapods把他加入了,那我們現在要使用就相當的簡單
如果想看相關導入的套件內容,可以從左側的Pods中去瀏覽,像下圖就是SQLite.swift的內容
首先,先在專案中加入一個Swift 檔案,我取名為SQLiteManager
接著,把SQLite套件加入
import SQLite
然後,將這個File檔相關的結構與參數設定一下
struct SQLiteManager {
var database: Connection!
init () {
}
}
我想很多人應該都跟我一樣,搞不懂Class、Struct、Enum的差異,這個之後我會找一天的議題來分享的,到那時後再說明囉!
等下我們會分幾個步驟完成,內容我會以資料欄位、類別最多的TB_EVENT為例,盡量能多提到就多提到,但還是focus在我們有用到的功能上,其他的就一樣提供補充參考資料供參:
好,那現在我們來開始吧!
首先,我們要設定連線,資料庫名稱為db.sqlite3、存放位置為/Document下方
mutating func connect(databaseName: String = "dailyWorkList.sqlite3") {
// 取得路徑
let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first! + "/" + databaseName
do {
// 若資料庫不存在的話,創立一個並建立連線
database = try Connection(path)
} catch {
print(“connection fail: \(error)")
}
}
再來,根據Day 3.設計的資料表格,我這邊都用變數先建立起來,方便後面重複使用到
let TB_EVENT = Table("TB_EVENT")
let TB_EVENT_ID = Expression<Int64>("id")
let TB_EVENT_DAY = Expression<String>("day")
let TB_EVENT_NAME = Expression<String>("name")
let TB_EVENT_TIME = Expression<String?>("time")
let TB_EVENT_CATEGORY = Expression<Int>("category")
let TB_EVENT_REMINDER = Expression<Bool>("reminder")
let TB_EVENT_PLACE = Expression<String?>("place")
let TB_EVENT_LAT = Expression<Double?>("lat")
let TB_EVENT_LNG = Expression<Double?>("lng")
let TB_EVENT_NOTE = Expression<String?>("note")
let TB_EVENT_FINISH = Expression<Bool>("finish")
順道提一下,Swift 的變數類型跟SQLite的變數類型不完全相同噢!SQLite的類型只有五種:
接著利用這些變數來建立資料表
try database.run(TB_EVENT.create(ifNotExists: true) { t in
t.column(TB_EVENT_ID, primaryKey: true) // "event_id" INTEGER PRIMARY KEY NOT NULL,
t.column(TB_EVENT_DAY, check: TB_EVENT_DAY.length == 8) // "day" TEXT NOT NULL
t.column(TB_EVENT_NAME) // "name" TEXT NOT NULL
t.column(TB_EVENT_TIME, check: TB_EVENT_DAY.length == 4) // "time" TEXT NOT NULL
t.column(TB_EVENT_CATEGORY, defaultValue: 0) // "category" INTEGER
t.column(TB_EVENT_REMINDER, defaultValue: false) // "reminder" INTEGER 0 or 1
t.column(TB_EVENT_PLACE) // "place" TEXT
t.column(TB_EVENT_LAT) // "lat" REAL
t.column(TB_EVENT_LNG) // "lng" REAL
t.column(TB_DAY_NOTE) // "note" TEXT
t.column(TB_EVENT_FINISH, defaultValue: false) // "finish" INTEGER 0 or 1
})
可以看到幾個可以提一下的東西
如此就完成了我們資料表的創建(Create);查詢方面,SQLite使用prepare()做SELECT的功能、filter()做WHERE條件的篩選,先設想之後會用到的功能,大概會有兩個:
func queryEventByDate(date: String) -> Array<Any> {
var list: Array<Any> = Array()
do {
list = Array(try database.prepare(TB_EVENT.filter(TB_EVENT_DAY == date)))
} catch {
print(“query fail: \(error)")
}
return list
}
func queryEventById(id: Int64) -> Array<Any> {
var list: Array<Any> = Array()
do {
list = Array(try database.prepare(TB_EVENT.filter(TB_EVENT_ID == id)))
} catch {
print(“query fail: \(error)")
}
return list
}
新增的話,就是我們畫面上按下Save後的動作,會把名稱、日期、時間、分類、是否提醒、座標、Note都寫入
func insertEvent(day: String, name: String, time: String?, category: Int, reminder: Bool, place: String?, lat: Double?, lng: Double?, note: String?) {
do {
try database.run(TB_EVENT.insert(TB_EVENT_DAY <- day, TB_EVENT_NAME <- name, TB_EVENT_TIME <- time, TB_EVENT_CATEGORY <- category, TB_EVENT_REMINDER <- reminder, TB_EVENT_PLACE <- place, TB_EVENT_LAT <- lat, TB_EVENT_LNG <- lng, TB_EVENT_NOTE <- note))
} catch {
print(“insert fail: \(error)")
}
}
修改部分,一樣是用Id作為Key值,畫面之後會建立,長得會跟新增的很像,只是少掉時間設定區間,改成唯讀的文字,另外增加是否完成的欄位
func updateEventById(id: Int64, name: String, time: String?, category: Int, reminder: Bool, place: String?, lat: Double?, lng: Double?, note: String, finish: Bool) {
do {
let item = TB_EVENT.filter(TB_EVENT_ID == id)
if try database.run(item.update(TB_EVENT_NAME <- name, TB_EVENT_TIME <- time, TB_EVENT_CATEGORY <- category, TB_EVENT_REMINDER <- reminder, TB_EVENT_PLACE <- place, TB_EVENT_LAT <- lat, TB_EVENT_LNG <- lng, TB_EVENT_NOTE <- note, TB_EVENT_FINISH <- finish)) > 0 {
print("update event")
}
} catch {
print(“update fail: \(error)")
}
}
刪除也是用Id,都仰賴filter()
func deleteEventById(id: Int64) {
let item = TB_EVENT.filter(TB_EVENT_ID == id)
do {
if try database.run(item.delete()) > 0 {
print("deleted event")
}
} catch {
print("delete failed: \(error)")
}
}
比照這個方式,把其他幾個Table都建立好後,調整一下init(),在初始化時就先建立連線和資料表
init () {
connect()
setTable()
}
接著在AppDelegate.swift中加入SqlManager,讓App在啟動的時候就可以建立SqlManager並初始化,方便之後的使用
let sqlManager: SQLiteManager = SQLiteManager()
此時,測試Run一下,會發現檔案多了一個sqlite的資料喔!