Swift學(xué)習教程之SQLite的基礎(chǔ)使用
前言
在我們的日常開發(fā)中,經(jīng)常會遇到用戶斷網(wǎng)或者網(wǎng)絡(luò)較慢的情況,這樣用戶在一進入頁面的時候會顯示空白的頁面,那么如何避免沒網(wǎng)顯示空白頁面的尷尬呢?答案就是:先在網(wǎng)絡(luò)好的時候緩存一部分數(shù)據(jù),這樣當下次網(wǎng)絡(luò)情況不好的時候,至少用戶可以先看到之前緩存的內(nèi)容,已達到提高APP的用戶體驗。
SQLite就是我們實現(xiàn)本地數(shù)據(jù)緩存的一種方案,SQLite有以下優(yōu)點:iOS內(nèi)嵌SQLite;經(jīng)過時間的驗證;開源;跨平臺。
OK,廢話不多說,現(xiàn)在我們就開始進入SQLite的體驗之旅。當然在開始之前我們要做一點準備工作,畢竟我們不打沒有準備的仗。
準備工作
創(chuàng)建備用數(shù)據(jù)
- 導(dǎo)入SQLite3:import SQLite3
- 創(chuàng)建一個Goods的類用來表示數(shù)據(jù)庫存儲的數(shù)據(jù)類型
- 創(chuàng)建一個Goods類型的數(shù)組
- 聲明一個dbPath和db的全局變量,聲明一個獲取libraryDirectory路徑的函數(shù)(數(shù)據(jù)庫存放路徑如何選擇)
代碼如下:
class Goods { let name: String! let weight: Int! var price: Double! init(name: String, weight: Int, price: Double) { self.name = name self.weight = weight self.price = price } } let goods = Goods(name: "computer", weight: 10, price: 2000.0) var goodArr = [Goods]() var dbPath = "" var db: OpaquePointer? func createData() { for index in 0...4 { let goods = Goods(name: "computer" + "\(index)", weight: index * 10, price: 20.0) goodArr.append(goods) } } func fetchLibraryPath() { if let libraryPathString = NSSearchPathForDirectoriesInDomains(.libraryDirectory, .userDomainMask, true).first { let pathURL = URL(fileURLWithPath: libraryPathString).appendingPathComponent("goods.sqlite") dbPath = pathURL.path } }
創(chuàng)建并連接數(shù)據(jù)庫
func openDatabase() -> OpaquePointer? { var db: OpaquePointer? if sqlite3_open(dbPath, &db) == SQLITE_OK { resultLabel.text = "成功打開數(shù)據(jù)庫,路徑:\(dbPath)" return db } else { resultLabel.text = "打開數(shù)據(jù)庫失敗" return nil } }
通過上面的代碼我們可以看到,首先聲明了一個OpaquePointer類型的可選值db,接下來調(diào)用了sqlite3_open()方法,該方法的作用是:如果之前創(chuàng)建了數(shù)據(jù)庫那么直接打開,若沒創(chuàng)建會直接創(chuàng)建一個。如果該方法調(diào)用成功,他會返回一個OpaquePointer的值賦值給你傳遞進去的db。
SQLITE_OK是一個定義在SQLite庫中的一個常量,它代表一個Int32的0。SQLite的大多數(shù)函數(shù)都會返回一個Int32的值,例如SQLITE_ROW (100)、SQLITE_DONE (101)等,詳細列表你可以查看這里。
現(xiàn)在你可以通過調(diào)用db = openDatabase()來打開或者創(chuàng)建一個數(shù)據(jù)庫了,正常情況下你會看見成功打開數(shù)據(jù)庫,路徑:xxx/xxx.sqlite的輸出。
現(xiàn)在,我們已經(jīng)成功的創(chuàng)建了一個名字為goods.sqlite的數(shù)據(jù)庫了,接下來我們要做的就是創(chuàng)建一個表了。
創(chuàng)建表
代碼
func createTable() { let createTableString = """ CREATE TABLE Computer( Id INT PRIMARY KEY NOT NULL, Name CHAR(255), Weight Int, Price Float); """ var createTableStatement: OpaquePointer? // 第一步 if sqlite3_prepare_v2(db, createTableString, -1, &createTableStatement, nil) == SQLITE_OK { // 第二步 if sqlite3_step(createTableStatement) == SQLITE_DONE { resultLabel.text = "成功創(chuàng)建表" } else { resultLabel.text = "未成功創(chuàng)建表" } } else { } //第三步 sqlite3_finalize(createTableStatement) }
代碼說明
首先解釋一下createTableString:創(chuàng)建一個名字為Computer的表,Id為主鍵且不為空,Name不超過255個字符,Weight為Int類型,Price為Float類型。
然后創(chuàng)建了一個OpaquePointer?類型的變量用于下面的函數(shù):sqlite3_prepare_v2()。
- 第一步:該函數(shù)會將createTableString編譯為字節(jié)代碼(byte code)并返回一個status code,這個函數(shù)執(zhí)行成功則表明database已經(jīng)準備好了執(zhí)行任意的SQL statement(就是創(chuàng)建的SQL的字符串),該函數(shù)執(zhí)行成功后即會執(zhí)行sqlite3_step()。
- 第二步:sqlite3_step()用來執(zhí)行編譯完成的statement handle(createTableStatement)并返回一個status code。
- 第三步:在你每一次的操作完成后你必須調(diào)用sqlite3_finalize()去刪除你的statement以避免resource leak。注意:一旦一個statement被finalized,你不應(yīng)該再一次使用它。
插入一條數(shù)據(jù)
代碼
func insertOneData() { let insertRowString = "INSERT INTO Computer (Id, Name, Weight, Price) VALUES (?, ?, ?, ?);" var insertStatement: OpaquePointer? //第一步 if sqlite3_prepare_v2(db, insertRowString, -1, &insertStatement, nil) == SQLITE_OK { let id: Int32 = 1 //第二步 sqlite3_bind_int(insertStatement, 1, id) sqlite3_bind_text(insertStatement, 2, goods.name, -1, nil) sqlite3_bind_int(insertStatement, 3, Int32(goods.weight)) sqlite3_bind_double(insertStatement, 4, goods.price) //第三步 if sqlite3_step(insertStatement) == SQLITE_DONE { resultLabel.text = "插入數(shù)據(jù)成功" } else { resultLabel.text = "插入數(shù)據(jù)失敗" } } else { } //第四步 sqlite3_finalize(insertStatement) }
代碼說明
- insertRowString中的?和前面的字段是對應(yīng)的,它只是占位符的意思,告訴編譯器當真正執(zhí)行該語句的時候會插入相應(yīng)的值。
- 第二步:sqlite3_bind_int()標識你綁定了一個Int類型的值,該函數(shù)的第一個參數(shù)是你的statement(即insertStatement),第二個參數(shù)是?的位置在你的statement(注意該值是非零的),在此處也就是1,第三個參數(shù)為你想綁定的值。sqlite3_bind_text()函數(shù)表示你綁定的是一個text(一般用于比較長的字符串)類型值,該函數(shù)比sqlite3_bind_int()多了額外的兩個參數(shù),第四個參數(shù)的意思是text的字節(jié)數(shù),一般穿-1,第五個參數(shù)是一個closure回調(diào),處理完string后調(diào)用。
- 第三步第四步同上
插入多條數(shù)據(jù)
代碼
func insertMutipleData() { let insertRowString = "INSERT INTO Computer (Id, Name, Weight, Price) VALUES (?, ?, ?, ?);" var insertStatement: OpaquePointer? //第一步 if sqlite3_prepare_v2(db, insertRowString, -1, &insertStatement, nil) == SQLITE_OK { for (index, good) in goodArr.enumerated() { let id: Int32 = Int32(index + 1) //第二步 sqlite3_bind_int(insertStatement, 1, id) sqlite3_bind_text(insertStatement, 2, good.name, -1, nil) sqlite3_bind_int(insertStatement, 3, Int32(good.weight)) sqlite3_bind_double(insertStatement, 4, good.price) //第三步 if sqlite3_step(insertStatement) == SQLITE_DONE { resultLabel.text = "插入數(shù)據(jù)成功" } else { resultLabel.text = "插入數(shù)據(jù)失敗" } //第四步 sqlite3_reset(insertStatement) } } else { } //第五步 sqlite3_finalize(insertStatement) }
代碼說明
- insertRowString同上。
- 第四步:調(diào)用sqlite3_reset()函數(shù),以便下次循環(huán)再次執(zhí)行insertStatement
- 第一步、第二步、第三步、第五步同上。
更新數(shù)據(jù)
代碼
func updateData() { let updateString = "UPDATE Computer SET Name = 'changeComputer' WHERE Id = 2;" var updateStatement: OpaquePointer? //第一步 if sqlite3_prepare_v2(db, updateString, -1, &updateStatement, nil) == SQLITE_OK { //第二步 if sqlite3_step(updateStatement) == SQLITE_DONE { resultLabel.text = "更新成功" } else { } } //第三步 sqlite3_finalize(updateStatement) }
代碼說明
- updateString:將Id==2的數(shù)據(jù)的Name字段改為changeComputer。
- sqlite3_prepare_v2():準備,sqlite3_step():執(zhí)行更新statement,sqlite3_finalize():結(jié)束。
刪除數(shù)據(jù)
代碼
func deleteData() { let deleteString = "DELETE FROM Computer WHERE Id = 2;" var deleteStatement: OpaquePointer? //第一步 if sqlite3_prepare_v2(db, deleteString, -1, &deleteStatement, nil) == SQLITE_OK { //第二步 if sqlite3_step(deleteStatement) == SQLITE_DONE { resultLabel.text = "刪除成功" } } else { } //第三步 sqlite3_finalize(deleteStatement) }
代碼說明
- deleteString:刪除表中Id==2的數(shù)據(jù)。
- sqlite3_prepare_v2():準備,sqlite3_step():執(zhí)行刪除statement,sqlite3_finalize():結(jié)束。
查詢一條數(shù)據(jù)
代碼
func queryOneData() { let queryString = "SELECT * FROM Computer WHERE Id == 2;" var queryStatement: OpaquePointer? //第一步 if sqlite3_prepare_v2(db, queryString, -1, &queryStatement, nil) == SQLITE_OK { //第二步 if sqlite3_step(queryStatement) == SQLITE_ROW { //第三步 let id = sqlite3_column_int(queryStatement, 0) let queryResultName = sqlite3_column_text(queryStatement, 1) let name = String(cString: queryResultName!) let weight = sqlite3_column_int(queryStatement, 2) let price = sqlite3_column_double(queryStatement, 3) resultLabel.text = "id: \(id), name: \(name), weight: \(weight), price: \(price)" } else { resultLabel.text = "error" } } //第四步 sqlite3_finalize(queryStatement) }
代碼說明
- queryString:在Computer表中查找所有Id == 2的數(shù)據(jù)。
- 第二步:注意此時要判斷的status code為SQLITE_ROW,如果該判斷為true則代表你查詢的數(shù)據(jù)存在在表里。
- 第三步:sqlite3_column_int()函數(shù)是按照列數(shù)取數(shù)據(jù),第一個參數(shù)是statement,第二個參數(shù)則是該字段是第幾列(Id 為表里的第一列,從0開始計算)。sqlite3_column_text()要略微復(fù)雜一點,他需要轉(zhuǎn)換類型通過String(cString: queryResultName!)。
- 第一步、第四步同上
查詢多條數(shù)據(jù)
代碼
func queryAllData() { let queryString = "SELECT * FROM Computer;" var queryStatement: OpaquePointer? //第一步 if sqlite3_prepare_v2(db, queryString, -1, &queryStatement, nil) == SQLITE_OK { //第二步 while(sqlite3_step(queryStatement) == SQLITE_ROW) { //第三步 let id = sqlite3_column_int(queryStatement, 0) let queryResultName = sqlite3_column_text(queryStatement, 1) let name = String(cString: queryResultName!) let weight = sqlite3_column_int(queryStatement, 2) let price = sqlite3_column_double(queryStatement, 3) resultLabel.text = "id: \(id), name: \(name), weight: \(weight), price: \(price)" } } //第四步 sqlite3_finalize(queryStatement) }
代碼說明
- 第二步:此處為while循環(huán),當查詢到最后一行時會返回SQLITE_DONE狀態(tài)碼來結(jié)束。
- 第一步第三步第四步同上。
小結(jié)
通過上面我們可以總結(jié)出執(zhí)行一個statement的大概流程:sqlite3_prepare_v2():準備,sqlite3_step():執(zhí)行statement,sqlite3_finalize():結(jié)束。好了,到這里SQLite3的增刪改查基本操作也就完事了。下一篇我們來了解一下SQLite的進階用法。Bye~
好了,以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習或者工作具有一定的參考學(xué)習價值,謝謝大家對腳本之家的支持。
相關(guān)文章
Swift 3.0基礎(chǔ)學(xué)習之類與結(jié)構(gòu)體
最近在學(xué)swift 3.0,主要看的是蘋果的官方文檔,這里只是根據(jù)自己看官方文檔的理解所做的一些記錄,不是完整的翻譯,希望也對你有所幫助。下面這篇文章主要介紹了Swift 3.0基礎(chǔ)學(xué)習之類與結(jié)構(gòu)體的相關(guān)資料,需要的朋友可以參考借鑒,下面來一起看看吧。2017-03-03Swift免費短信驗證碼實現(xiàn)及動態(tài)倒計時功能
這篇文章主要介紹了Swift免費短信驗證碼實現(xiàn)及動態(tài)倒計時功能的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2017-02-02swift 錯誤處理do catch try try!使用詳解
這篇文章主要介紹了swift 錯誤處理do catch try try!使用詳解的相關(guān)資料,需要的朋友可以參考下2023-03-03