Swift之SQLite的基础使用

栏目: Swift · 发布时间: 7年前

内容简介:在我们的日常开发中,经常会遇到用户断网或者网络较慢的情况,这样用户在一进入页面的时候会显示空白的页面,那么如何避免没网显示空白页面的尴尬呢?答案就是:先在网络好的时候缓存一部分数据,这样当下次网络情况不好的时候,至少用户可以先看到之前缓存的内容,已达到提高APP的用户体验。      SQLite就是我们实现本地数据缓存的一种方案,SQLite有以下优点:iOS内嵌SQLite;经过时间的验证;开源;跨平台。 OK,废话不多说,现在我们就开始进入SQLite的体验之旅。当然在开始之前我们要做一点准备工作,毕

  在我们的日常开发中,经常会遇到用户断网或者网络较慢的情况,这样用户在一进入页面的时候会显示空白的页面,那么如何避免没网显示空白页面的尴尬呢?答案就是:先在网络好的时候缓存一部分数据,这样当下次网络情况不好的时候,至少用户可以先看到之前缓存的内容,已达到提高APP的用户体验。      SQLite就是我们实现本地数据缓存的一种方案,SQLite有以下优点:iOS内嵌SQLite;经过时间的验证;开源;跨平台。 OK,废话不多说,现在我们就开始进入 SQLite 的体验之旅。当然在开始之前我们要做一点准备工作,毕竟我们不打没有准备的仗。

准备工作

创建备用数据

  • 导入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 的数据库了,接下来我们要做的就是创建一个表了。

创建表

代码

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)
}
复制代码

代码说明

sqlite3_reset()

更新数据

代码

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 状态码来结束。
  • 第一步第三步第四步同上。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Art of Computer Programming, Volume 2

The Art of Computer Programming, Volume 2

Knuth, Donald E. / Addison-Wesley Professional / 1997-11-04 / USD 79.99

Finally, after a wait of more than thirty-five years, the first part of Volume 4 is at last ready for publication. Check out the boxed set that brings together Volumes 1 - 4A in one elegant case, and ......一起来看看 《The Art of Computer Programming, Volume 2》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器