SwiftUI 學習使用GRDB來進行SQLite的操作
xcode 13.4.1, swift 5.5, iOS 15.4
2022-08-31
App大部份都需要儲存一些資料,比如遊戲的分數等等,雖然Apple提供了Core Data來做類型SQL Database,但不太好用,如果可以使用原先的SQL來進行操作,就不需要再學習另一套Core Data的用法。
1. 在XCode按 File->Add Packages...
2. 在右上角輸入 https://github.com/groue/GRDB.swift.git,根據 https://github.com/groue/GRDB.swift中最高可以使用的版本是v.5.26.0,在Dependency Rule選擇Up to Next Major Version,並填入5.26.0
3. 按 Add Package
4. 選擇GRDB
5. 完成後,在Project Structure中的Package Dependencies看到GRDB已加入:
6. 在Target->General->Frameworks, Libraries, and Embeded Content也看到GRDB:
7. 建立一個playground,並輸入以下代碼:
import Foundation
import GRDB
func connectToDB(_ dbname : String) -> DatabaseQueue? {
let path = NSSearchPathForDirectoriesInDomains(
.documentDirectory, .userDomainMask, true
).first!
do {
let databaseQueue = try DatabaseQueue(path: "\(path)/\(dbname).sqlite")
return databaseQueue
} catch {
print("Error : \(error)")
return nil
}
}
let dbname = "testGRDB"
if let databaseQueue = connectToDB(dbname) {
print(databaseQueue)
}
8. 運行後應看到在相應的目錄中多了一個testGRDB.sqlite檔案。
9. 增加一個createPlayerTable方法,主要功能是在testGRDB.sqlite的數據庫中建立一個player的table,這個table有三個欄位,分別為id, name和score,並執行一次insert和fetch,運行完應該會看到console有一條記錄被打印出來:
import Foundation
import GRDB
func connectToDB(_ dbname : String) -> DatabaseQueue? {
let path = NSSearchPathForDirectoriesInDomains(
.documentDirectory, .userDomainMask, true
).first!
do {
let databaseQueue = try DatabaseQueue(path: "\(path)/\(dbname).sqlite")
return databaseQueue
} catch {
print("Error : \(error)")
return nil
}
}
func createPlayerTable(_ databseQueue : DatabaseQueue) {
do {
try databseQueue.write { db in
try db.create(table: "player") { t in
t.autoIncrementedPrimaryKey("id")
t.column("name", .text).notNull()
t.column("score", .integer).notNull()
}
}
} catch {
print("Error : \(error)")
}
}
struct Player: Codable, FetchableRecord, PersistableRecord {
var id: Int64
var name: String
var score: Int
}
func insertPlayer( _ databseQueue : DatabaseQueue, _ record : Player) {
do {
try databseQueue.write { db in
try record.insert(db)
}
} catch {
print("Error : \(error)")
}
}
let dbname = "testGRDB"
if let databaseQueue = connectToDB(dbname) {
createPlayerTable(databaseQueue)
let player = Player(id: 1, name: "JOHN", score: 100)
insertPlayer(databaseQueue, player)
let players: [Player] = try databaseQueue.read { db in
try Player.fetchAll(db)
}
players.forEach { player in
print(player)
}
}
10. 最後再增加一個deletePlayer方法,來刪除記錄,實作看下面:
import Foundation
import GRDB
func connectToDB(_ dbname : String) -> DatabaseQueue? {
let path = NSSearchPathForDirectoriesInDomains(
.documentDirectory, .userDomainMask, true
).first!
do {
let databaseQueue = try DatabaseQueue(path: "\(path)/\(dbname).sqlite")
return databaseQueue
} catch {
print("Error : \(error)")
return nil
}
}
func createPlayerTable(_ databseQueue : DatabaseQueue) {
do {
try databseQueue.write { db in
try db.create(table: "player") { t in
t.autoIncrementedPrimaryKey("id")
t.column("name", .text).notNull()
t.column("score", .integer).notNull()
}
}
} catch {
print("Error : \(error)")
}
}
struct Player: Codable, FetchableRecord, PersistableRecord {
var id: Int64
var name: String
var score: Int
}
func insertPlayer( _ databseQueue : DatabaseQueue, _ record : Player) {
do {
try databseQueue.write { db in
try record.insert(db)
}
} catch {
print("Error : \(error)")
}
}
func deletePlayer( _ databseQueue : DatabaseQueue, _ player : Player) {
do {
let _ = try databseQueue.write { db in
try player.delete(db)
}
} catch {
print("Error : \(error)")
}
}
let dbname = "testGRDB"
if let databaseQueue = connectToDB(dbname) {
createPlayerTable(databaseQueue)
let player = Player(id: 1, name: "JOHN", score: 100)
insertPlayer(databaseQueue, player)
let players: [Player] = try databaseQueue.read { db in
try Player.fetchAll(db)
}
players.forEach { player in
print(player)
}
deletePlayer(databaseQueue, players[0])
print("after delete.")
let newPlayers: [Player] = try databaseQueue.read { db in
try Player.fetchAll(db)
}
print("There are \(newPlayers.count) players in the db.")
}
11. 以上我們簡單了演示了如何使用GRDB來進行數據庫的Create, Read, Update 和 Delete。