Swift之SQLite的基础使用

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

内容简介:在我们的日常开发中,经常会遇到用户断网或者网络较慢的情况,这样用户在一进入页面的时候会显示空白的页面,那么如何避免没网显示空白页面的尴尬呢?答案就是:先在网络好的时候缓存一部分数据,这样当下次网络情况不好的时候,至少用户可以先看到之前缓存的内容,已达到提高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 状态码来结束。
  • 第一步第三步第四步同上。

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

查看所有标签

猜你喜欢:

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

Linux/UNIX系统编程手册

Linux/UNIX系统编程手册

Michael Kerrisk / 孙剑 许从年 董健、孙余强 郭光伟 陈舸 / 人民邮电出版社 / 2014-1 / 158

《linux/unix系统编程手册(上、下册)》是介绍linux与unix编程接口的权威著作。linux编程资深专家michael kerrisk在书中详细描述了linux/unix系统编程所涉及的系统调用和库函数,并辅之以全面而清晰的代码示例。《linux/unix系统编程手册(上、下册)》涵盖了逾500个系统调用及库函数,并给出逾200个程序示例,另含88张表格和115幅示意图。 《li......一起来看看 《Linux/UNIX系统编程手册》 这本书的介绍吧!

MD5 加密
MD5 加密

MD5 加密工具

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具