Swift之SQLite的基礎使用

前言

  在咱們的平常開發中,常常會遇到用戶斷網或者網絡較慢的狀況,這樣用戶在一進入頁面的時候會顯示空白的頁面,那麼如何避免沒網顯示空白頁面的尷尬呢?答案就是:先在網絡好的時候緩存一部分數據,這樣當下次網絡狀況很差的時候,至少用戶能夠先看到以前緩存的內容,已達到提升APP的用戶體驗。      SQLite就是咱們實現本地數據緩存的一種方案,SQLite有如下優勢:iOS內嵌SQLite;通過時間的驗證;開源;跨平臺。 OK,廢話很少說,如今咱們就開始進入SQLite的體驗之旅。固然在開始以前咱們要作一點準備工做,畢竟咱們不打沒有準備的仗。html

準備工做

建立備用數據

  • 導入SQLite3:import SQLite3
  • 建立一個Goods的類用來表示數據庫存儲的數據類型
  • 建立一個Goods類型的數組
  • 聲明一個dbPath和db的全局變量,聲明一個獲取libraryDirectory路徑的函數(數據庫存放路徑如何選擇

代碼以下:

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
    }
}
複製代碼

建立並鏈接數據庫

func openDatabase() -> OpaquePointer? {
    var db: OpaquePointer?
    if sqlite3_open(dbPath, &db) == SQLITE_OK {
        resultLabel.text = "成功打開數據庫,路徑:\(dbPath)"
        return db
    } else {
        resultLabel.text = "打開數據庫失敗"
        return nil
    }
}
複製代碼

  經過上面的代碼咱們能夠看到,首先聲明瞭一個OpaquePointer類型的可選值db,接下來調用了sqlite3_open()方法,該方法的做用是:若是以前建立了數據庫那麼直接打開,若沒建立會直接建立一個。若是該方法調用成功,他會返回一個OpaquePointer的值賦值給你傳遞進去的dbSQLITE_OK是一個定義在SQLite庫中的一個常量,它表明一個Int32的0。SQLite的大多數函數都會返回一個Int32的值,例如SQLITE_ROW (100)SQLITE_DONE (101)等,詳細列表你能夠查看這裏。 如今你能夠經過調用db = openDatabase()來打開或者建立一個數據庫了,正常狀況下你會看見成功打開數據庫,路徑:xxx/xxx.sqlite的輸出。 如今,咱們已經成功的建立了一個名字爲goods.sqlite的數據庫了,接下來咱們要作的就是建立一個表了。sql

建立表

代碼

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 = "成功建立表"
        } else {
            resultLabel.text = "未成功建立表"
        }
    } else {
            
    }
    //第三步
    sqlite3_finalize(createTableStatement)
}
複製代碼

代碼說明

  首先解釋一下createTableString:建立一個名字爲Computer的表,Id爲主鍵且不爲空,Name不超過255個字符,Weight爲Int類型,Price爲Float類型。 而後建立了一個OpaquePointer?類型的變量用於下面的函數:sqlite3_prepare_v2()數據庫

  • 第一步:該函數會將createTableString編譯爲字節代碼(byte code)並返回一個status code,這個函數執行成功則代表database已經準備好了執行任意的SQL statement(就是建立的SQL的字符串),該函數執行成功後即會執行sqlite3_step()
  • 第二步:sqlite3_step()用來執行編譯完成的statement handle(createTableStatement)並返回一個status code。
  • 第三步:在你每一次的操做完成後你必須調用sqlite3_finalize()去刪除你的statement以免resource leak。注意:一旦一個statement被finalized,你不該該再一次使用它。

插入一條數據

代碼

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 = "插入數據成功"
            } else {
                resultLabel.text = "插入數據失敗"
            }
    } else {
        
    }
    //第四步
    sqlite3_finalize(insertStatement)
}
複製代碼

代碼說明

  • insertRowString中的?和前面的字段是對應的,它只是佔位符的意思,告訴編譯器當真正執行該語句的時候會插入相應的值。
  • 第二步:sqlite3_bind_int()標識你綁定了一個Int類型的值,該函數的第一個參數是你的statement(即insertStatement),第二個參數是?的位置在你的statement(注意該值是非零的),在此處也就是1,第三個參數爲你想綁定的值。sqlite3_bind_text()函數表示你綁定的是一個text(通常用於比較長的字符串)類型值,該函數比sqlite3_bind_int()多了額外的兩個參數,第四個參數的意思是text的字節數,通常穿-1,第五個參數是一個closure回調,處理完string後調用。
  • 第三步第四步同上

插入多條數據

代碼

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 = "插入數據成功"
            } else {
                resultLabel.text = "插入數據失敗"
            }
            //第四步
            sqlite3_reset(insertStatement)
        }
    } else {
        
    }
    //第五步
    sqlite3_finalize(insertStatement)
}
複製代碼

代碼說明

  • insertRowString同上。
  • 第四步:調用sqlite3_reset()函數,以便下次循環再次執行insertStatement
  • 第一步、第二步、第三步、第五步同上。

更新數據

代碼

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的數據的Name字段改成changeComputer
  • sqlite3_prepare_v2():準備,sqlite3_step():執行更新statement,sqlite3_finalize():結束。

刪除數據

代碼

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的數據。
  • sqlite3_prepare_v2():準備,sqlite3_step():執行刪除statement,sqlite3_finalize():結束。

查詢一條數據

代碼

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的數據。
  • 第二步:注意此時要判斷的status code爲SQLITE_ROW,若是該判斷爲true則表明你查詢的數據存在在表裏。
  • 第三步:sqlite3_column_int()函數是按照列數取數據,第一個參數是statement,第二個參數則是該字段是第幾列(Id 爲表裏的第一列,從0開始計算)。sqlite3_column_text()要略微複雜一點,他須要轉換類型經過String(cString: queryResultName!)
  • 第一步、第四步同上

查詢多條數據

代碼

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循環,當查詢到最後一行時會返回SQLITE_DONE狀態碼來結束。
  • 第一步第三步第四步同上。

小結

經過上面咱們能夠總結出執行一個statement的大概流程:sqlite3_prepare_v2():準備,sqlite3_step():執行statement,sqlite3_finalize():結束。好了,到這裏SQLite3的增刪改查基本操做也就完事了。下一篇咱們來了解一下SQLite的進階用法。Bye~數組

相關文章
相關標籤/搜索