【问题标题】:SwiftUI SQLite ForEach list dataSwiftUI SQLite ForEach 列表数据
【发布时间】:2020-02-13 15:27:17
【问题描述】:

我正在尝试将 SQLite 数据库 (with SQLite.swift) 集成到我的项目中(因为我未恢复的 CoreData 明显限制引用了 here

我有一个帮助文件,其中包含一个我实例化的类来完成与 SQLite 查询有关的所有繁重工作。

我不知道如何在 SwiftUI 中的 ForEach 语句中获取该数据,比如一个简单的数据库内容列表。

我试图从运行查询的函数中设置一个返回值,但它的返回类型是AnySequence<Row>,我不知道该怎么做。当我在获取数据后尝试返回它时,我收到关于不返回失败的错误(可以理解)。在这种情况下,不知道如何返回空白 AnySequence<Row>。请参阅下面的代码。

有什么想法吗?

来自帮助类的代码(按照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)
        }
    }
}

和简单的 SwiftUI 内容视图


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")
            }
        }
    }
}

理论上,我希望能够在我的 VStack 中做类似的事情:

ForEach (myData.listUsers, id: \.self) { record in 
      Text("UserName \(record.userName)")
}

我试图让 listUsers 函数返回它的结果,以便可以像这样使用它,但效果并不好..

更新 #1

尝试让函数返回数据,然后我可以在 SwiftUI 视图中对其进行迭代。我正在尝试这个:

    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")
    }

然后在我试图调用的视图中:

                let response = myData.listUsers()
                for resp in response {
                    Text(resp.name)
                }

然后我得到错误:

类型'(Int, String, String)'不符合协议'Sequence'

更新 #2

Holy C*&@ - 多么痛苦..

我能够让函数返回我可以使用的东西,但这绝对不是最有效的方法。知道如何才能做得更好:

我现在的功能是:

    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
    }


}

它返回一个字符串字典数组:任何(因为我在我的数据库中混合了字符串和整数。那么我的函数看起来像:

                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")
                 }

那么它在做什么,很荒谬,就是循环遍历数组,然后循环遍历字典得到键值对..

只是感觉很麻烦而且过于复杂。

  • 仍然无法弄清楚如何将其放入实际视图中。我可以将输出打印到日志中,但不能在 Text() 标记中..

【问题讨论】:

    标签: ios swift xcode sqlite swiftui


    【解决方案1】:

    我发现了如何做到这一点:

    在我的 SQLite 工作文件中,我需要创建一个结构来表示数据模型:

    struct TestDataModel: Hashable {
        let id: Int
        let name: String
        let email: String
    }
    

    然后在我的助手类中,我的函数将数据加载到一个 TestDataModel 对象数组中。然后该函数返回这样的数组:

        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
         }
    

    然后,在我的 SwiftUI 视图中,我可以像往常一样使用 TestDataModel 对象数组:

                ForEach (myData.listUsers2(), id: \.self) { record in
                    Text(record.email)
    
                }
    

    这行得通,不确定它是否是最优雅的方法,但结果很好..

    【讨论】:

      猜你喜欢
      • 2021-10-28
      • 2022-11-10
      • 1970-01-01
      • 1970-01-01
      • 2022-11-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多