SwiftUI SQLite ForEach 列表数据 [英] SwiftUI SQLite ForEach list data
问题描述
我正在尝试将 SQLite 数据库 (使用 SQLite.swift) 集成到我的项目中(因为我未恢复的 CoreData 明显限制在此处引用.
我有一个帮助文件,其中包含一个我实例化的类来完成与 SQLite 查询有关的所有繁重工作.
我不知道如何在 SwiftUI 的 ForEach 语句中获取这些数据,让我们说一个简单的数据库内容列表.
我试图从运行查询的函数中设置一个返回值,但它的返回类型是 AnySequence
,我不确定如何处理它.当我在获取数据后尝试返回它时,我收到关于不返回失败的错误(可以理解).在这种情况下,不知道如何返回空白的 AnySequence
.请参阅下面的代码.
有什么想法吗?
来自帮助程序类的代码(按照 Kilo Loco 的 YouTube 视频中的一些说明构建:
<预><代码>进口基金会导入 SQLite类数据模型{var 数据库:连接!让 usersTable = Table("users")let id = Expression和简单的 SwiftUI 内容查看
<预><代码>导入 SwiftUI让 myData = DataModel()结构内容视图:查看{@State var 名称:String = ""@State var 电子邮件:String = ""var主体:一些视图{虚拟堆栈{TextField("输入姓名", text: self.$name)TextField("输入邮箱", text: self.$email)按钮(动作:{myData.insertRecord(name: self.$name.wrappedValue, email: self.$email.wrappedValue)}) {文本(插入记录")}按钮(动作:{myData.createTable()}) {文本(创建表")}按钮(动作:{myData.listUsers()}) {Text("列出用户")}}}}理论上,我希望能够在我的 VStack 中做一些事情:
ForEach (myData.listUsers, id: \.self) { 记录在文本(用户名\(记录.用户名)")}
我试图让 listUsers 函数返回它的结果,这样就可以像这样使用它,但效果不佳..
更新 #1
尝试让函数返回数据,然后我可以在 SwiftUI 视图中对其进行迭代.我正在尝试这个:
func listUsers() ->(整数,字符串,字符串){打印(列出的用户")做{让用户 = 尝试 self.database.prepare(self.usersTable)对于用户中的用户{打印(用户ID:\(用户[self.id]),用户名:\(用户[self.name]),电子邮件:\(用户[self.email])")返回(用户[self.id],用户[self.name],用户[self.email])}}抓住{打印(错误)}return (0, "No Name", "No Email")}
然后在我试图调用的视图中:
让 response = myData.listUsers()响应响应{文本(resp.name)}
但我随后收到错误:
<块引用>类型 '(Int, String, String)' 不符合协议 'Sequence'
更新 #2
Holy C*&@ - 好痛苦..
我能够让函数返回一些我可以使用的东西,但这绝对不是最有效的方法.知道如何做得更好:
我现在的功能是:
func listUsers() ->[字典<字符串,任何>] {打印(列出的用户")做{让用户 = 尝试 self.database.prepare(self.usersTable)对于用户中的用户{打印(用户ID:\(用户[self.id]),用户名:\(用户[self.name]),电子邮件:\(用户[self.email])")dataDictArray.append(["id":user[self.id], "name":user[self.name], "email":user[self.email]])}}抓住{打印(错误)}返回数据字典数组}}
它返回一个字符串字典数组:Any(因为我在我的数据库中混合了 String 和 Int.然后我的函数看起来像:
让 response = myData.listUsers()打印(响应)对于响应中的 dicts {用于记录在 dicts {if (record.key.datatypeValue == "name") {print("记录键:\(record.key)")print("记录值:\(record.value)")}}}}) {Text("列出用户")}
那么它在做什么,这是荒谬的,是遍历数组,然后遍历字典以获取键值对..
只是感觉很麻烦而且过于复杂.
- 仍然无法弄清楚如何将其放入实际视图中.我可以将输出打印到日志中,但不能打印在 Text() 标签中.
我发现了如何做到这一点:
在我的 SQLite 工作文件中,我需要创建一个结构来表示数据模型:
struct TestDataModel: Hashable {让 ID:Int让名称:字符串让电子邮件:字符串}
然后在我的助手类中,我的函数将数据加载到 TestDataModel 对象数组中.该函数然后像这样返回数组:
func listUsers2() ->[测试数据模型] {打印(列出的用户")var theseVars = [TestDataModel]()做{让用户 = 尝试 self.database.prepare(self.usersTable)对于用户中的用户{打印(用户ID:\(用户[self.id]),用户名:\(用户[self.name]),电子邮件:\(用户[self.email])")这些Vars.append(TestDataModel(id: user[self.id], name: user[self.name], email: user[self.email]))}}抓住{打印(错误)}返回这些变量}
然后,在我的 SwiftUI 视图中,我可以像平常一样使用 TestDataModel 对象数组:
ForEach (myData.listUsers2(), id: \.self) { 记录在文本(记录.电子邮件)}
这有效,不确定它是否是最优雅的方法,但结果很好..
I am trying to integrate an SQLite database (with SQLite.swift) into my project (since my unrecovered apparent limitations of CoreData referenced here.
Ive got a helper file with a class that I instantiate to do all of the heavy lifting with regards to SQLite queries.
I can not figure out how to get that data, let's say a simple list of the contents of the database, into a ForEach statement in SwiftUI.
I have tried to set a return from the function that runs the query, but its return type is AnySequence<Row>
, and I'm not sure what to do with that. When I try to return it after the data is fetched, I get errors about not returning is on failure (understandably so). Don't know how to return a blank AnySequence<Row>
in that case. See code below.
Any thoughts?
Code from helper class (built following some of the instructions at Kilo Loco's YouTube video:
import Foundation
import SQLite
class DataModel {
var database: Connection!
let usersTable = Table("users")
let id = Expression<Int>("id")
let name = Expression<String>("name")
let email = Expression<String>("email")
var dataDict = [Dictionary<String, String>()]
init() {
do {
let documentDirectory = try FileManager.default.url(for: .applicationSupportDirectory, in: .allDomainsMask, appropriateFor: nil, create: true)
let fileUrl = documentDirectory.appendingPathComponent("users").appendingPathExtension("sqlite3")
let database = try Connection(fileUrl.path)
self.database = database
print("Database initialized at path \(fileUrl)")
} catch {
print(error)
}
}
func createTable() {
print("Create Tapped")
let createTable = self.usersTable.create { (table) in
table.column(self.id, primaryKey: true)
table.column(self.name)
table.column(self.email, unique: true)
}
do {
try self.database.run(createTable)
print("Table Created")
} catch {
print(error)
}
}
func insertRecord(name: String, email: String) {
let insertRecord = self.usersTable.insert(self.name <- name, self.email <- email)
do {
try self.database.run(insertRecord)
print("record added")
} catch {
print(error)
}
}
func listUsers() {
print("Listed Users")
do {
let users = try self.database.prepare(self.usersTable)
for user in users {
print("User ID: \(user[self.id]), UserName: \(user[self.name]), Email: \(user[self.email])")
}
} catch {
print(error)
}
}
}
and simple SwiftUI content View
import SwiftUI
let myData = DataModel()
struct ContentView: View {
@State var name: String = ""
@State var email: String = ""
var body: some View {
VStack {
TextField("Enter Name", text: self.$name)
TextField("Enter email", text: self.$email)
Button(action: {
myData.insertRecord(name: self.$name.wrappedValue, email: self.$email.wrappedValue)
}) {
Text("Insert Record")
}
Button(action: {
myData.createTable()
}) {
Text("Create Table")
}
Button(action: {
myData.listUsers()
}) {
Text("List users")
}
}
}
}
In theory, what I would like to be able to do is something like in my VStack:
ForEach (myData.listUsers, id: \.self) { record in
Text("UserName \(record.userName)")
}
I was trying to have the listUsers function return its result so it could be used like this, but that did not work out so well..
Update #1
Trying to have the function return the data, then I can iterate over it in the SwiftUI View. I was trying this:
func listUsers() -> (Int, String, String) {
print("Listed Users")
do {
let users = try self.database.prepare(self.usersTable)
for user in users {
print("User ID: \(user[self.id]), UserName: \(user[self.name]), Email: \(user[self.email])")
return (user[self.id], user[self.name], user[self.email])
}
} catch {
print(error)
}
return (0, "No Name", "No Email")
}
and then in the View I was trying to call:
let response = myData.listUsers()
for resp in response {
Text(resp.name)
}
but I then get the error:
Type '(Int, String, String)' does not conform to protocol 'Sequence'
Update #2
Holy C*&@ - What a pain..
I was able to get the function to return something that I can work with, but it is most definitely not the most efficient way to do this. Any idea how I can do it better:
My function now is:
func listUsers() -> [Dictionary<String,Any>] {
print("Listed Users")
do {
let users = try self.database.prepare(self.usersTable)
for user in users {
print("User ID: \(user[self.id]), UserName: \(user[self.name]), Email: \(user[self.email])")
dataDictArray.append(["id":user[self.id], "name":user[self.name], "email":user[self.email]])
}
} catch {
print(error)
}
return dataDictArray
}
}
Which returns an Array of Dictionary of String:Any (because I'm mixing String and Int in my database. Then my function looks like:
let response = myData.listUsers()
print(response)
for dicts in response {
for record in dicts {
if (record.key.datatypeValue == "name") {
print("Record Key: \(record.key)")
print("Record Value: \(record.value)")
}
}
}
}) {
Text("List users")
}
So what its doing, which is ridiculous, is looping through the array, then looping through the dictionary to get the key value pairs..
It just feels cumbersome and overly complicated.
- Still can't figure out how to get it into the actual view. I can print the output to the log, but not in a Text() tag..
Ive discovered how to do this:
in my SQLite worker file, I needed to create a struct to represent the data model:
struct TestDataModel: Hashable {
let id: Int
let name: String
let email: String
}
Then in my helper class, my function loads the data into an array of TestDataModel objects. The function then returns the array like this:
func listUsers2() -> [TestDataModel] {
print("Listed Users")
var theseVars = [TestDataModel]()
do {
let users = try self.database.prepare(self.usersTable)
for user in users {
print("User ID: \(user[self.id]), UserName: \(user[self.name]), Email: \(user[self.email])")
theseVars.append(TestDataModel(id: user[self.id], name: user[self.name], email: user[self.email]))
}
} catch {
print(error)
}
return theseVars
}
Then, in my SwiftUI view, I can use the array of TestDataModel objects like normal:
ForEach (myData.listUsers2(), id: \.self) { record in
Text(record.email)
}
This works, not sure if its the most elegant approach, but results are good..
这篇关于SwiftUI SQLite ForEach 列表数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!