为了真正存储消息我们需要使用数据库SQLite开设新的一个文件夹DataBaseManager来管理数据库创建一个新的同名文件。能用结构体就用结构体。能不用到数据库的地方就不要用数据库的稳定性不强容易在版本更新的时候出问题。尤其是1.0版本不要用数据库。1.使用系统自带的 SQLite 库导入 SQLite 库点击项目文件在 “General” 选项卡下向下滚动到 “Frameworks, Libraries, and Embedded Content”。点击加号选择libsqlite3.tbd然后点击Add。配置 Bridging Header桥接头文件将以下内容添加到桥接头文件#importsqlite3.h2.使用第三方库FMDB使用FMDB第三方库来管理数据库。编辑Podfile文件在目标下添加podFMDB在工程文件目录下安装库podinstall安装成功在DataBaseManager页面导入importFoundationimportFMDB可以用结构体就用结构体来构建数据库structDataBaseManager{}初始化数据库使用单例模式方便在其他页面调用该数据库的方法。structDataBaseManager{staticletshared:DataBaseManagerDataBaseManager()vardatabase:FMDatabase!//使用FMDatabaseinit(){//这里添加需要用到的方法}}同时在AppDelegate页面加载数据库DataBaseManager()创建数据库mutatingfuncinitalizeDataBase(){}结构体和枚举在 Swift 中是值类型默认情况下成员方法是不能修改self或属性的。通过标记为mutating可以在方法中改变属性的值。在这个上下文中mutating确保可以安全地修改database属性因为database是一个属性表示 SQLite 数据库的实例。要创建数据库要在存储数据库的位置将其命名并创建。为了防止创建失败使用try?记得在最后把数据库的名称加上letfileURLtry?FileManager.default.url(for:.documentDirectory,in:.userDomainMask,appropriateFor:nil,create:false).appendingPathComponent(chat_database.sqlite)databaseFMDatabase(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: )快速创建init(){initalizeDataBase()//这里添加需要用到的方法}mutatingfuncinitalizeDataBase(){//创建数据库的地址URL再把文件名加在后面letfileURLtry?FileManager.default.url(for:.documentDirectory,in:.userDomainMask,appropriateFor:nil,create:false).appendingPathComponent(chat_database.sqlite)databaseFMDatabase(url:fileURL)ifdatabase.open(){print(数据库可以打开)}else{print(数据库大概打开失败)}}}if database.open()尝试打开数据库连接如果可以打开则可以使用该数据库。最后把这个方法添加到初始化中调用。创建数据库的表表一般存储这几种数据VARCHAR 文本(String)使用的时候后面要加括号代表存储的数据字节。TEXT 文本(String)FLOAT 浮点数(float)BOOLEAN 布尔值(Bool)INTERGER 整型(Int)表的名字取名叫chat。funccreateTable(){letcreateTableQueryCREATE 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 一般主键都叫IDPRIMARY KEY修饰表示这个是主键。INTERGER表示这个键的数据类型。AUTOINCREMENT表示键值自动递增1…2…这样递增CREATE TABLE IF NOT EXISTS这个是固定用法了, 不存在的时候就创建表。这里把message其他键的就是”名字 数据类型”这样罗列的。注意数据类型必须是大写。其实就是这里的部分。把chatID转为INTEGER//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.0funccreateTable(){letcreateTableQueryCREATE 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 (?, ?, …)表示要插入的内容先用?表示funcinsertData(chatModel:ChatTextModel){letinsertQueryINSERT INTO chat(chatID,content... ) VALUES (?,?, ...)try?database.executeUpdate(insertQuery,values:[Int(chatModel.chatID)??0,chatModel.content...])}继续用executeUpdate(_:values:)执行SQL语句再把要用到的值放在数组里传进来。完整代码如下。funcinsertData(chatModels:ChatTextModel){letinsertQueryINSERT 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()DataBaseManager.shared.insertData(chatModels:newmodel)获取数据库数据现在就可以把发送的消息存在数据库里了。但是怎么取出来用呢聊天记录是一个ChatModel形式的数组[ChatModel]所以函数返回值是这个数组先定义一个空数组。funcfetchData()-[ChatTextModel]{varchatModels:[ChatTextModel][]returnchatModels}使用**SELECT * FROM 表名称查询语句获取表内的所有记录。**先把语句写好在查询的时候再用。letqueryStringSELECT * FROM chat意思是从chat表中选择所有记录。返回的结果将包括该表中每一行的所有列。funcfetchData()-[ChatTextModel]{varchatModels:[ChatTextModel][]letqueryStringSELECT * FROM chatifletresultstry?database.executeQuery(queryString,values:nil){whileresults.next(){letmessageIDresults.int(forColumn:ID)chatModels.append(ChatTextModel(chatID:#T##String#,messageID:\(messageID),content:#T##String#,target:#T##String#,mineHead:#T##String#,otherHead:#T##String#))}}returnchatModels}}如果查询到了就将它们添加进model中database.executeQuery(queryString, values: nil)执行查询功能的方法因为查询不需要参数则填写nil。查询并提取数据的时候才需要用.executeQuery获取数据库中的数据遍历全部数据并在加载聊天记录时将它们添加到model中。ifletresultstry?database.executeQuery(queryString,values:nil){}results对象这是一个FMResultSet类型的对象表示数据库查询返回的结果集。它包含了根据 SQL 查询从数据库中检索到的数据。next()方法将结果集的游标指针移动到下一行。如果存在下一行则next()返回true如果没有更多的行可供访问返回false。每次调用next()游标就向后移动一行逐行读取结果集中的数据。用while遍历 results.next()中每一行的数据**results.int(forColumn: ID)**获取ID行的Int整型值)whileresults.next(){letmessageIDresults.int(forColumn:ID)添加到Model中chatModels.append(ChatTextModel(chatID:#T##String#,messageID:\(messageID),content:#T##String#,target:#T##String#,mineHead:#T##String#,otherHead:#T##String#))funcfetchData()-[ChatTextModel]{varchatmodels:[ChatTextModel][]letfetchQuerySELECT * FROM chatifletresultstry?database.executeQuery(fetchQuery,values:nil){whileresults.next(){letmessageIDresults.int(forColumn:ID)letchatIDresults.string(forColumn:chatID)??letcontentresults.string(forColumn:content)??lettargetresults.string(forColumn:target)??letmingHeadresults.string(forColumn:mindHead)??letotherHeadresults.string(forColumn:otherHead)??lettyperesults.string(forColumn:type)??letaddressresults.string(forColumn:address)??letlatituderesults.double(forColumn:latitude)letlongituderesults.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(查询失败)}returnchatmodels}3.打开包内容用sqlitebrowser软件查看数据库内容就是这个文件。然后可以看见为数据库创建的表这是发送的聊天信息可以看到已经被存到数据库里了
Swift学习笔记29-数据库SQlite
发布时间:2026/5/20 3:49:21
为了真正存储消息我们需要使用数据库SQLite开设新的一个文件夹DataBaseManager来管理数据库创建一个新的同名文件。能用结构体就用结构体。能不用到数据库的地方就不要用数据库的稳定性不强容易在版本更新的时候出问题。尤其是1.0版本不要用数据库。1.使用系统自带的 SQLite 库导入 SQLite 库点击项目文件在 “General” 选项卡下向下滚动到 “Frameworks, Libraries, and Embedded Content”。点击加号选择libsqlite3.tbd然后点击Add。配置 Bridging Header桥接头文件将以下内容添加到桥接头文件#importsqlite3.h2.使用第三方库FMDB使用FMDB第三方库来管理数据库。编辑Podfile文件在目标下添加podFMDB在工程文件目录下安装库podinstall安装成功在DataBaseManager页面导入importFoundationimportFMDB可以用结构体就用结构体来构建数据库structDataBaseManager{}初始化数据库使用单例模式方便在其他页面调用该数据库的方法。structDataBaseManager{staticletshared:DataBaseManagerDataBaseManager()vardatabase:FMDatabase!//使用FMDatabaseinit(){//这里添加需要用到的方法}}同时在AppDelegate页面加载数据库DataBaseManager()创建数据库mutatingfuncinitalizeDataBase(){}结构体和枚举在 Swift 中是值类型默认情况下成员方法是不能修改self或属性的。通过标记为mutating可以在方法中改变属性的值。在这个上下文中mutating确保可以安全地修改database属性因为database是一个属性表示 SQLite 数据库的实例。要创建数据库要在存储数据库的位置将其命名并创建。为了防止创建失败使用try?记得在最后把数据库的名称加上letfileURLtry?FileManager.default.url(for:.documentDirectory,in:.userDomainMask,appropriateFor:nil,create:false).appendingPathComponent(chat_database.sqlite)databaseFMDatabase(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: )快速创建init(){initalizeDataBase()//这里添加需要用到的方法}mutatingfuncinitalizeDataBase(){//创建数据库的地址URL再把文件名加在后面letfileURLtry?FileManager.default.url(for:.documentDirectory,in:.userDomainMask,appropriateFor:nil,create:false).appendingPathComponent(chat_database.sqlite)databaseFMDatabase(url:fileURL)ifdatabase.open(){print(数据库可以打开)}else{print(数据库大概打开失败)}}}if database.open()尝试打开数据库连接如果可以打开则可以使用该数据库。最后把这个方法添加到初始化中调用。创建数据库的表表一般存储这几种数据VARCHAR 文本(String)使用的时候后面要加括号代表存储的数据字节。TEXT 文本(String)FLOAT 浮点数(float)BOOLEAN 布尔值(Bool)INTERGER 整型(Int)表的名字取名叫chat。funccreateTable(){letcreateTableQueryCREATE 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 一般主键都叫IDPRIMARY KEY修饰表示这个是主键。INTERGER表示这个键的数据类型。AUTOINCREMENT表示键值自动递增1…2…这样递增CREATE TABLE IF NOT EXISTS这个是固定用法了, 不存在的时候就创建表。这里把message其他键的就是”名字 数据类型”这样罗列的。注意数据类型必须是大写。其实就是这里的部分。把chatID转为INTEGER//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.0funccreateTable(){letcreateTableQueryCREATE 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 (?, ?, …)表示要插入的内容先用?表示funcinsertData(chatModel:ChatTextModel){letinsertQueryINSERT INTO chat(chatID,content... ) VALUES (?,?, ...)try?database.executeUpdate(insertQuery,values:[Int(chatModel.chatID)??0,chatModel.content...])}继续用executeUpdate(_:values:)执行SQL语句再把要用到的值放在数组里传进来。完整代码如下。funcinsertData(chatModels:ChatTextModel){letinsertQueryINSERT 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()DataBaseManager.shared.insertData(chatModels:newmodel)获取数据库数据现在就可以把发送的消息存在数据库里了。但是怎么取出来用呢聊天记录是一个ChatModel形式的数组[ChatModel]所以函数返回值是这个数组先定义一个空数组。funcfetchData()-[ChatTextModel]{varchatModels:[ChatTextModel][]returnchatModels}使用**SELECT * FROM 表名称查询语句获取表内的所有记录。**先把语句写好在查询的时候再用。letqueryStringSELECT * FROM chat意思是从chat表中选择所有记录。返回的结果将包括该表中每一行的所有列。funcfetchData()-[ChatTextModel]{varchatModels:[ChatTextModel][]letqueryStringSELECT * FROM chatifletresultstry?database.executeQuery(queryString,values:nil){whileresults.next(){letmessageIDresults.int(forColumn:ID)chatModels.append(ChatTextModel(chatID:#T##String#,messageID:\(messageID),content:#T##String#,target:#T##String#,mineHead:#T##String#,otherHead:#T##String#))}}returnchatModels}}如果查询到了就将它们添加进model中database.executeQuery(queryString, values: nil)执行查询功能的方法因为查询不需要参数则填写nil。查询并提取数据的时候才需要用.executeQuery获取数据库中的数据遍历全部数据并在加载聊天记录时将它们添加到model中。ifletresultstry?database.executeQuery(queryString,values:nil){}results对象这是一个FMResultSet类型的对象表示数据库查询返回的结果集。它包含了根据 SQL 查询从数据库中检索到的数据。next()方法将结果集的游标指针移动到下一行。如果存在下一行则next()返回true如果没有更多的行可供访问返回false。每次调用next()游标就向后移动一行逐行读取结果集中的数据。用while遍历 results.next()中每一行的数据**results.int(forColumn: ID)**获取ID行的Int整型值)whileresults.next(){letmessageIDresults.int(forColumn:ID)添加到Model中chatModels.append(ChatTextModel(chatID:#T##String#,messageID:\(messageID),content:#T##String#,target:#T##String#,mineHead:#T##String#,otherHead:#T##String#))funcfetchData()-[ChatTextModel]{varchatmodels:[ChatTextModel][]letfetchQuerySELECT * FROM chatifletresultstry?database.executeQuery(fetchQuery,values:nil){whileresults.next(){letmessageIDresults.int(forColumn:ID)letchatIDresults.string(forColumn:chatID)??letcontentresults.string(forColumn:content)??lettargetresults.string(forColumn:target)??letmingHeadresults.string(forColumn:mindHead)??letotherHeadresults.string(forColumn:otherHead)??lettyperesults.string(forColumn:type)??letaddressresults.string(forColumn:address)??letlatituderesults.double(forColumn:latitude)letlongituderesults.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(查询失败)}returnchatmodels}3.打开包内容用sqlitebrowser软件查看数据库内容就是这个文件。然后可以看见为数据库创建的表这是发送的聊天信息可以看到已经被存到数据库里了