为了真正存储消息,我们需要使用数据库SQLite
开设新的一个文件夹DataBaseManager来管理数据库,创建一个新的同名文件。能用结构体就用结构体。
能不用到数据库的地方就不要用,数据库的稳定性不强,容易在版本更新的时候出问题。尤其是1.0版本,不要用数据库。
1.使用系统自带的 SQLite 库
-
导入 SQLite 库:
- 点击项目文件,在 "General" 选项卡下,向下滚动到 "Frameworks, Libraries, and Embedded Content"。
- 点击加号(
+),选择libsqlite3.tbd,然后点击Add。
-
配置 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软件查看数据库内容,就是这个文件。

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

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

