Swift学习笔记29-数据库SQlite

为了真正存储消息,我们需要使用数据库SQLite

开设新的一个文件夹DataBaseManager来管理数据库,创建一个新的同名文件。能用结构体就用结构体。

能不用到数据库的地方就不要用,数据库的稳定性不强,容易在版本更新的时候出问题。尤其是1.0版本,不要用数据库。

1.使用系统自带的 SQLite 库

  1. 导入 SQLite 库

    • 点击项目文件,在 "General" 选项卡下,向下滚动到 "Frameworks, Libraries, and Embedded Content"。
    • 点击加号(+),选择 libsqlite3.tbd,然后点击 Add
  2. 配置 Bridging Header桥接头文件

    将以下内容添加到桥接头文件:

    objectivec 复制代码
    #import<sqlite3.h>

2.使用第三方库FMDB

使用FMDB第三方库来管理数据库。

  • 编辑 Podfile 文件,在目标下添加:

    复制代码
    pod'FMDB'
  • 在工程文件目录下安装库:

    复制代码
    podinstall

安装成功

在DataBaseManager页面导入

swift 复制代码
import Foundation
import FMDB

可以用结构体就用结构体来构建数据库

swift 复制代码
struct DataBaseManager {
    
}

初始化数据库

使用单例模式方便在其他页面调用该数据库的方法。

swift 复制代码
struct DataBaseManager {
    static let shared: DataBaseManager = DataBaseManager()
    var database: FMDatabase! //使用FMDatabase
    init() {
      //这里添加需要用到的方法
    }
}

同时在AppDelegate页面加载数据库

swift 复制代码
DataBaseManager()

创建数据库

swift 复制代码
mutating func initalizeDataBase() {}
  • 结构体和枚举在 Swift 中是值类型,默认情况下,成员方法是不能修改 self 或属性的。通过标记为 mutating,可以在方法中改变属性的值。
  • 在这个上下文中,mutating 确保可以安全地修改 database 属性,因为 database 是一个属性,表示 SQLite 数据库的实例。

要创建数据库,要在存储数据库的位置将其命名并创建。为了防止创建失败,使用try?,记得在最后把数据库的名称加上

swift 复制代码
let fileURL = try? FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false).appendingPathComponent("chat_database.sqlite")
        database = FMDatabase(url: fileURL)
  • url(for:in:appropriateFor:create:) 创建一个 URL,指向设备的"文档目录",这是应用数据存储的标准位置。
    • for: .documentDirectory 指定要获取文档目录的 URL。
    • in: .userDomainMask 表示应用的用户域。
    • appropriateFor: nil 是一个参数,预留位置,通常用于给定的文件 URL。
    • create: false 意味着如果目录不存在则不创建。
  • appendingPathComponent("chat_base.sqlite") 将数据库文件名 chat_base.sqlite 附加到上面生成的目录 URL,以便最终得到数据库文件的完整路径。
  • 使用FMDatabase(url: )快速创建
swift 复制代码
 init() {
        initalizeDataBase()
        //这里添加需要用到的方法
    }
    mutating func initalizeDataBase() {
        //创建数据库的地址URL,再把文件名加在后面
        let fileURL = try? FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false).appendingPathComponent("chat_database.sqlite")
        database = FMDatabase(url: fileURL)
        if database.open() {
            print("数据库可以打开")
        } else {
            print("数据库大概打开失败")
        }
    }
}

if database.open() 尝试打开数据库连接,如果可以打开,则可以使用该数据库。最后把这个方法添加到初始化中调用。

创建数据库的表

表一般存储这几种数据:

  • VARCHAR 文本(String)

使用的时候后面要加括号,代表存储的数据字节。

  • TEXT 文本(String)
  • FLOAT 浮点数(float)
  • BOOLEAN 布尔值(Bool)
  • INTERGER 整型(Int)

表的名字取名叫chat。

swift 复制代码
func createTable() {
        let createTableQuery = "CREATE TABLE IF NOT EXIST chat (ID INTEGER PRIMARY KEY AUTOINCREMENT, chatID INTEGER, content TEXT, target TEXT, mineHead TEXt, otherHead TEXT, type TEXT, filePath TEXT, address TEXT, latitude FLOAT, longitude FLOAT)"
    }

chat表示表的名字

ID INTERGER PRIMARY KEY 一般主键都叫ID,PRIMARY KEY修饰表示这个是主键。

INTERGER表示这个键的数据类型。

AUTOINCREMENT表示键值自动递增,1...2...这样递增

CREATE TABLE IF NOT EXISTS这个是固定用法了, 不存在的时候就创建表。这里把message

其他键的就是"名字 + 数据类型"这样罗列的。注意数据类型必须是大写。

其实就是这里的部分。把chatID转为INTEGER

swift 复制代码
//var chatID: String
//var messageID: String
//var content: String
//var target: String
//var mineHead: String
//var otherHead: String
//var type: String = "text"//就是说这个model的type默认是"text",也可以是其他
//var filePath: String = "" //文件路径
//var address: String = ""
//var latitude: Double = 0.0
//var longitude: Double = 0.0

swift 复制代码
func createTable() {
        let createTableQuery = "CREATE TABLE IF NOT EXIST chat (ID INTEGER PRIMARY KEY AUTOINCREMENT, chatID INTEGER, content TEXT, target TEXT, mineHead TEXt, otherHead TEXT, type TEXT, filePath TEXT, address TEXT, latitude FLOAT, longitude FLOAT)"
        try? database.executeUpdate(createTableQuery, values: [])
    }

database.executeUpdate(...) 方法

  • executeUpdate(_:values:)FMDatabase 类中的一个方法,主要用于执行 SQL 更新语句,比如创建表、插入、更新或删除数据。
  • 该方法接受两个参数:第一个参数是 SQL 语句(以字符串形式给出),第二个参数是一个数组,包含 SQL 语句要用到的参数值。在创建表的情况下,通常不需要实际的值,所以使用一个空数组就足够了。

记得调用这个方法**createTable()**

在表中根据键插入值

需要从ChatTextModel找要传的数据,所以先把它作为参数传进来.

先写一个插入用的语句

这里就只需要键名了。

INSERT INTO 表名(表键1, 表键2, ...)

VALUE (?, ?, ...)表示要插入的内容,先用?表示

swift 复制代码
func insertData(chatModel: ChatTextModel) {
        let insertQuery = "INSERT INTO chat(chatID,content... ) VALUES (?,?, ...)"
        try? database.executeUpdate(insertQuery, values: [Int(chatModel.chatID) ?? 0, chatModel.content...])
        
    }

继续用executeUpdate(_:values:) 执行SQL语句,再把要用到的值放在数组里传进来。

完整代码如下。

swift 复制代码
    func insertData(chatModels: ChatTextModel) {
        let insertQuery = "INSERT INTO chat (chatID, content, target, mineHead, otherHead, type, filePath, address, latitude, longitude) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
        try? database.executeUpdate(insertQuery, values: [Int(chatModels.chatID) ?? 0, chatModels.content, chatModels.target, chatModels.mineHead, chatModels.otherHead, chatModels.type, chatModels.filePath, chatModels.address, chatModels.latitude, chatModels.longitude])
    }

现在回到ChatViewController,把发送消息时添加进newmodel的操作,添加进数据库内。取代newmodel.save()

swift 复制代码
DataBaseManager.shared.insertData(chatModels: newmodel)

获取数据库数据

现在就可以把发送的消息存在数据库里了。但是怎么取出来用呢?

聊天记录是一个ChatModel形式的数组[ChatModel],所以函数返回值是这个数组,先定义一个空数组。

swift 复制代码
func fetchData() -> [ChatTextModel] {
        var chatModels: [ChatTextModel] = []
        
        return chatModels
    }

使用**"SELECT * FROM 表名称" 查询语句,获取表内的所有记录。**

先把语句写好,在查询的时候再用。

swift 复制代码
let queryString = "SELECT * FROM chat"

意思是从 chat 表中选择所有记录。返回的结果将包括该表中每一行的所有列。

swift 复制代码
func fetchData() -> [ChatTextModel] {
        var chatModels: [ChatTextModel] = []
        let queryString = "SELECT * FROM chat"
        
        if let results = try? database.executeQuery(queryString, values: nil) {
            while results.next() {
                let messageID = results.int(forColumn: "ID")
                chatModels.append(ChatTextModel(chatID: <#T##String#>, messageID: "\(messageID)", content: <#T##String#>, target: <#T##String#>, mineHead: <#T##String#>, otherHead: <#T##String#>))
            }
            
        }
        return chatModels
    }
}

如果查询到了,就将它们添加进model中

database.executeQuery(queryString, values: nil) 执行查询功能的方法,因为查询不需要参数,则填写nil。查询并提取数据的时候才需要用.executeQuery

获取数据库中的数据,遍历全部数据,并(在加载聊天记录时)将它们添加到model中。
swift 复制代码
if let results = try? database.executeQuery(queryString, values: nil) { }
  • results 对象 :这是一个 FMResultSet 类型的对象,表示数据库查询返回的结果集。它包含了根据 SQL 查询从数据库中检索到的数据。
  • next() 方法
    • 将结果集的游标(指针)移动到下一行。如果存在下一行,则 next() 返回 true;如果没有更多的行可供访问,返回 false
    • 每次调用 next(),游标就向后移动一行,逐行读取结果集中的数据。
用while遍历 results.next()中每一行的数据

**results.int(forColumn: "ID")**获取ID行的Int(整型值)

swift 复制代码
while results.next() {
                let messageID = results.int(forColumn: "ID")
添加到Model中
swift 复制代码
chatModels.append(ChatTextModel(chatID: <#T##String#>, messageID: "\(messageID)", content: <#T##String#>, target: <#T##String#>, mineHead: <#T##String#>, otherHead: <#T##String#>))
swift 复制代码
func fetchData() -> [ChatTextModel] {
        var chatmodels: [ChatTextModel] = []
        let fetchQuery = "SELECT * FROM chat"
        if let results = try? database.executeQuery(fetchQuery, values: nil) {
            while results.next() {
                let messageID = results.int(forColumn: "ID")
                let chatID = results.string(forColumn: "chatID") ?? ""
                let content = results.string(forColumn: "content") ?? ""
                let target = results.string(forColumn: "target") ?? ""
                let mingHead = results.string(forColumn: "mindHead") ?? ""
                let otherHead = results.string(forColumn: "otherHead") ?? ""
                let type = results.string(forColumn: "type") ?? ""
                let address = results.string(forColumn: "address") ?? ""
                let latitude = results.double(forColumn: "latitude")
                let longitude = results.double(forColumn: "longitude")
                chatmodels.append(ChatTextModel(chatID: chatID, messageID: "\(messageID)", content: content, target: target, mineHead: mingHead, otherHead: otherHead, type: type, address: address, latitude: latitude, longitude: longitude))
            }
        } else {
            print("查询失败")
        }
        return chatmodels
    }

3.打开包内容,用sqlitebrowser软件查看数据库内容,就是这个文件。

然后可以看见为数据库创建的表

这是发送的聊天信息,可以看到已经被存到数据库里了

相关推荐
知识分享小能手3 小时前
Flask入门学习教程,从入门到精通, 认识Flask —— 知识点详解 (1)
python·学习·flask
xwz小王子3 小时前
SkiP:让模仿学习学会“快进“——动作重标记如何在不改架构的情况下削减机器人 15-40% 的执行步数
学习·架构·机器人
weixin_520649873 小时前
数据库局部变量,全局变量,流程控制
数据库
GEO从入门到精通3 小时前
GEO学习与传统SEO学习有什么区别?
人工智能·学习·microsoft
想唱rap3 小时前
IO多路转接Select
运维·服务器·网络·数据库·sql·tcp/ip·mysql
csjane10793 小时前
Redis 配置文件
数据库·redis·缓存
_codemonster3 小时前
系统分析师案例刷题(八)数据库
数据库
Yushan Bai4 小时前
ORACLE SQL Performance Analyzer (SPA) 测试流程
数据库·sql
俊哥工具4 小时前
不用安装不收费!多功能U盘修复工具,解决大部分U盘故障
学习·pdf·word·excel·音视频