当前位置: 首页 > news >正文

Swift学习笔记29-数据库SQlite

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

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

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

1.使用系统自带的 SQLite 库

  1. 导入 SQLite 库

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

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

    #import<sqlite3.h>

2.使用第三方库FMDB

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

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

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

    podinstall

安装成功

在DataBaseManager页面导入

importFoundationimportFMDB

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

structDataBaseManager{}

初始化数据库

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

structDataBaseManager{staticletshared:DataBaseManager=DataBaseManager()vardatabase:FMDatabase!//使用FMDatabaseinit(){//这里添加需要用到的方法}}

同时在AppDelegate页面加载数据库

DataBaseManager()

创建数据库

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

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

letfileURL=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: )快速创建
init(){initalizeDataBase()//这里添加需要用到的方法}mutatingfuncinitalizeDataBase(){//创建数据库的地址URL,再把文件名加在后面letfileURL=try?FileManager.default.url(for:.documentDirectory,in:.userDomainMask,appropriateFor:nil,create:false).appendingPathComponent("chat_database.sqlite")database=FMDatabase(url:fileURL)ifdatabase.open(){print("数据库可以打开")}else{print("数据库大概打开失败")}}}

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

创建数据库的表

表一般存储这几种数据:

  • VARCHAR 文本(String)

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

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

表的名字取名叫chat。

funccreateTable(){letcreateTableQuery="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

//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

funccreateTable(){letcreateTableQuery="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 (?, ?, …)表示要插入的内容,先用?表示

funcinsertData(chatModel:ChatTextModel){letinsertQuery="INSERT INTO chat(chatID,content... ) VALUES (?,?, ...)"try?database.executeUpdate(insertQuery,values:[Int(chatModel.chatID)??0,chatModel.content...])}

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

完整代码如下。

funcinsertData(chatModels:ChatTextModel){letinsertQuery="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()

DataBaseManager.shared.insertData(chatModels:newmodel)

获取数据库数据

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

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

funcfetchData()->[ChatTextModel]{varchatModels:[ChatTextModel]=[]returnchatModels}

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

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

letqueryString="SELECT * FROM chat"

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

funcfetchData()->[ChatTextModel]{varchatModels:[ChatTextModel]=[]letqueryString="SELECT * FROM chat"ifletresults=try?database.executeQuery(queryString,values:nil){whileresults.next(){letmessageID=results.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中。
ifletresults=try?database.executeQuery(queryString,values:nil){}
  • results对象:这是一个FMResultSet类型的对象,表示数据库查询返回的结果集。它包含了根据 SQL 查询从数据库中检索到的数据。
  • next()方法
    • 将结果集的游标(指针)移动到下一行。如果存在下一行,则next()返回true;如果没有更多的行可供访问,返回false
    • 每次调用next(),游标就向后移动一行,逐行读取结果集中的数据。
用while遍历 results.next()中每一行的数据

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

whileresults.next(){letmessageID=results.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]=[]letfetchQuery="SELECT * FROM chat"ifletresults=try?database.executeQuery(fetchQuery,values:nil){whileresults.next(){letmessageID=results.int(forColumn:"ID")letchatID=results.string(forColumn:"chatID")??""letcontent=results.string(forColumn:"content")??""lettarget=results.string(forColumn:"target")??""letmingHead=results.string(forColumn:"mindHead")??""letotherHead=results.string(forColumn:"otherHead")??""lettype=results.string(forColumn:"type")??""letaddress=results.string(forColumn:"address")??""letlatitude=results.double(forColumn:"latitude")letlongitude=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("查询失败")}returnchatmodels}

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

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

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

http://www.cnnetsun.cn/news/2464165.html

相关文章:

  • CodeWave项目导出实战:从云端到本地的完整避坑指南(含数据库配置与端口冲突解决)
  • Kubernetes Ingress Controller 深度解析:从入门到精通
  • OpenCV实战:用Triangle和Maxentropy算法搞定文档扫描与OCR预处理
  • 【独家首发】Gemini Ultra未公开API限流机制曝光:3类高频报错代码对应的真实QPS阈值与绕过方案
  • Rust内存安全:所有权、借用与生命周期深度解析
  • 从光伏MPPT到手机快充:拆解Boost电路在不同场景下的Matlab建模核心差异
  • 深入解析Arm Cortex-A53 Cache架构:从原理到多核一致性与性能优化实践
  • ARM PMU性能监控原理与缓存优化实战
  • 为什么你的Gemini Gmail智能回复总在关键邮件失效?——从LLM token截断到上下文窗口压缩的底层归因分析
  • 苹果app上架卡审核的底层逻辑(经验分享)
  • Spring Cloud Gateway配置HTTPS后,微服务调用报NotSslRecordException?一个配置项帮你搞定
  • 手把手教你无损转换:把老电脑的Legacy启动盘改成UEFI+GPT(附DiskGenius详细操作图)
  • C# CAD二次开发实战:掌握Editor类核心选择方法,实现高效范围选择
  • 2024实战指南 | 拆解BombLab:从汇编调试到系统理解
  • 麒麟V10 SP2服务器mate-indicators内存泄漏?别慌,手把手教你定位和修复(附离线包下载)
  • Autodesk Eagle vs. Altium Designer:轻量级PCB工具入门,聊聊界面、库和操作逻辑的真实差异
  • 一文详解供应链:华为的供应链怎么做?
  • ARM PMU架构解析与性能优化实践
  • Redis分布式锁进阶第一十三篇
  • 别再手动敲了!用C#写个程序,让倍加福RFID读头自动填表(附TCP通讯源码)
  • Stegsolve隐写分析从入门到实战:除了LSB,这些Analyse功能你都会用了吗?
  • MySQl安装
  • 全志V853开发板驱动7寸RGB屏:Linux DRM设备树配置与调试实战
  • AI硬件能效革命:光子计算与自旋电子技术解析
  • 告别Bundle包:手把手教你用tar.gz源码方式安装Horizon Client for Linux(附依赖清单)
  • ARMv8/v9架构TLB原理与优化实践
  • Simscape Electrical电机控制仿真完整教程:从入门到精通的5步实践指南
  • 推挽 开漏 高阻
  • Qt新手也能搞定的GPU加速图片渲染:用QOpenGLWidget和QImage实现高性能显示
  • 别再为资源发愁!我整理的M芯片Mac装Win10+Office全套资源包与避坑要点