如何在 SwiftUI 中的 firebase 查询期间显示加载动画

2023-11-30

我正在使用 SwiftUI 构建一个应用程序,并有一个 ObservableObject 用于查询我的 Firestore 数据库。我的文档相对较大,并且经常需要查询很多文档,因此我想在查询下载数据时加入某种加载指示器。

这是我创建的 ObservableObject 的示例:

import FirebaseFirestore
import SwiftUI

struct Document: Identifiable, Equatable {
    var id: String
    var content: String
}

class Fetch: ObservableObject {
    init(loading: Binding<Bool>) {
        self._loading = loading
        readDocuments()
    }
    
    @Published var documents: [Document] = []
    @Binding var loading: Bool
    
    var collection: CollectionReference = Firestore.firestore().collection("DOCUMENTS")
    
    func newDocument(content: String) {
        let id = self.collection.document().documentID
        self.collection.document(id).setData(["id": id, "content": content]) { (error) in handleError(error: error, message: "\(id) CREATED") }
    }
    
    func deleteDocument(document: Document) {
        if self.documents.contains(document) {
            self.collection.document(document.id).delete() { (error) in handleError(error: error, message: "\(document.id) DELETED") }
        } else { print("\(document.id) NOT FOUND") }
    }
    
    func updateDocument(document: Document, update: [String : Any]) {
        if self.documents.contains(document) {
            self.collection.document(document.id).updateData(update) { (error) in handleError(error: error, message: "\(document.id) UPDATED") }
        } else { print("\(document.id) NOT FOUND") }
    }
    
    func readDocuments() {
        self.collection.addSnapshotListener { (snapshot, error) in
            handleError(error: error, message: "READ DOCUMENTS")
            snapshot?.documentChanges.forEach({ (change) in
                if change.type == .added {
                    self.loading = true
                    self.documents.append(Document(id: change.document.get("id") as? String ?? "FAILED TO READ",
                                                   content: change.document.get("content") as? String ?? "FAILED TO READ"))
                    self.loading = false
                }
                if change.type == .modified {
                    self.loading = true
                    self.documents = self.documents.map { (document) -> Document in
                        if document.id == change.document.documentID {
                            let modifiedDocument = Document(id: change.document.get("id") as? String ?? "FAILED TO READ",
                                                 content: change.document.get("content") as? String ?? "FAILED TO READ")
                            return modifiedDocument
                        } else {
                            return document
                        }
                    }
                    self.loading = false
                }
                if change.type == .removed {
                    self.loading = true
                    self.documents.removeAll(where: { $0.id == change.document.documentID })
                    self.loading = false
                }
                
            })
        }
    }
    
}

func handleError(error: Error?, message: String) {
    if error != nil { print((error?.localizedDescription)!); return } else { print(message) }
}

这是我创建的示例视图:

struct ContentView: View {
    @State var loading: Bool = false
    var body: some View {
        NavigationView {
            if loading {
                Color.blue.overlay(Text("Loading View"))
            } else {
                Subview(fetch: Fetch(loading: self.$loading))
            }
        }
    }
}

struct Subview: View {
    @ObservedObject var fetch: Fetch
    @State var newDocumentContent: String = ""
    
    var body: some View {
        VStack(spacing: 0.0) {
            List {
                ForEach(self.fetch.documents) { document in
                    NavigationLink(destination:
                    UpdateDocument(fetch: self.fetch, documentID: document.id)) {
                        Text(document.content)
                    }
                }.onDelete { indexSet in
                    self.deleteDocument(indexSet: indexSet)
                }
            }
            
            Divider()
            
            NewDocument(fetch: self.fetch, newDocumentContent: self.$newDocumentContent)
        }.navigationBarTitle("CRUD", displayMode: .inline)
    }
    
    func deleteDocument(indexSet: IndexSet) {
        self.fetch.deleteDocument(document: self.fetch.documents[indexSet.first!])
    }
}

请记住,对于这个示例,数据并没有那么大,不需要加载视图,这几乎是即时的,但对于我的应用程序来说,此代码被分成不同文件和场景的负载,所以我想我应该创建这个示例。

我尝试添加一个绑定布尔值并在加载 readData() 函数时切换它,但 SwiftUI 获取地图并且出现错误。

“在视图更新期间修改状态,这将导致未定义的行为。”


你需要使用@Published in the @ObservableObject (not @Binding).

这是一个可能的演示:

class Fetch: ObservableObject {
    @Published var loading = false

    func longTask() {
        self.loading = true
        // simulates a long asynchronous task (eg. fetching data)
        DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
            self.loading = false
        }
    }
}
struct ContentView: View {
    @ObservedObject private var fetch = Fetch()

    var body: some View {
        ZStack {
            Text("Main view")
            if fetch.loading {
                LoadingView() // can be replaced with any other loading indicator/view
            }
        }
        .onAppear {
            self.fetch.longTask()
        }
    }
}
struct LoadingView: View {
    var body: some View {
        ZStack {
            Color.black
                .opacity(0.5)
                .edgesIgnoringSafeArea(.all)
            Text("Loading")
        }
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在 SwiftUI 中的 firebase 查询期间显示加载动画 的相关文章

随机推荐

  • 如何仅在特定目标的 makefile 中使用 .NOTPARALLEL?

    我在 Makefile 中有 5 个标签 all label1 label2 label3 label4 last label I want last label最后完成 我想使用make j 如果我使用 NOTPARALLEL 这将使他们
  • java.lang.SecurityException:权限拒绝:需要 com.huawei.android.launcher.permission.WRITE_SETTINGS

    当应用程序在手机 HUAWEI ALE 21 Android 6 0 API 23 上运行时 我遇到了这个问题 我的应用程序崩溃了 我收回了那些错误 java lang SecurityException Permission Denial
  • 从应用程序调用默认主屏幕

    我需要从我的应用程序调用手机附带的默认主屏幕 这也是一个主屏幕应用程序 我尝试过搜索并找到这个 ArrayList
  • Netty SSL 主机名验证支持

    据我所知 没有可以用来在 Netty 中启用 SSL 主机名验证的 标志 或配置设置 我见过使用 SslHandler handshake 返回的 ChannelFuture 添加自定义实现的示例 ChannelFuture handsha
  • 不允许主机 xxxx 连接到此 MySQL 服务器

    好吧 在阅读同名主题但没有成功后 我不得不再次询问并向您展示我的场景 我在 Kali Linux 机器上 我的 mysql 配置文件 etc my cnf 是这样设置的 bind address 172 16 1 228 我重置了服务 无论
  • C 预处理器:自己实现 __COUNTER__

    我目前正在使用 COUNTER 我的 C 库代码中的宏来生成唯一的整数标识符 它工作得很好 但我看到两个问题 它不是任何 C 或 C 标准的一部分 也使用的独立代码 COUNTER 可能会感到困惑 因此我希望实现一个相当于 COUNTER
  • AttributeError:'function'对象没有属性'sum'pandas

    我在 Pandas 中有以下数据框 count group 11 99435 Bachelor 64900 Just 12 162483 Some College 61782
  • 向非 C++ 程序员解释 C++ SFINAE

    C 中的 SFINAE 是什么 您能用不懂 C 的程序员可以理解的语言解释一下吗 另外 SFINAE 对应于 Python 这样的语言中的什么概念 警告 这是一个really很长的解释 但希望它不仅能真正解释 SFINAE 的作用 还能让您
  • 使用 maven-compiler-plugin 进行 Maven 注释处理

    我尝试编译包含生成源代码的注释的代码 我用maven compiler plugin and build helper maven plugin 我的 POM 看起来像这样
  • 无法将模块函数传递给页面

    我有一个名为util用方法getMutedColor和其他一些 getMutedColor依赖于另一个称为rand在同一模块中 page includeJs https cdnjs cloudflare com ajax libs d3 3
  • 对吊装感到困惑

    考虑这两个略有不同的提升版本 mylocation dublin function outputPosition alert mylocation mylocation fingal alert mylocation outputPosit
  • 如何将数据库中某些表的所有权从 postgres 更改为另一个用户?

    我有一个包含大量表的数据库 有些表由 postgres 用户拥有 而不是我创建的 我想将这些表的所有权转移给我创建的表 因为在进行 django migrations 时 您只能为 psql 连接设置一个用户和密码 并且该用户无权访问 po
  • PHP中获取iframe的父url

    我正在创建一个将在 IFrame 中加载的小部件 用户将能够将该小部件放置在自己的网站上 如何获取在 javascript 和 或 PHP 中使用 IFrame 的网站的 URL IFrame 加载一个 php 文件 我在 IFrame 页
  • jQuery 与 PHP - 性能比较

    从性能角度来看 哪个是更好的解决方案 这是一个非常小的例子 PHP 脚本向 jQuery 返回一个数字 需要检查该数字是否为1 页面需要显示 1 人 否则为 X 人 PHP 脚本进行此检查并返回 x 个人 会更快 还是 jQuery 在获取
  • 如何在本地主机上启动 cxf 服务但在 wsdl 中返回外部地址?

    我在apache后面使用cxf和jetty通过soap公开web服务 目标是启动码头http 本地主机 9000在所有情况下都有 apache 代理 但让自动生成的 wsdl 显示一个适合其运行环境的soap address 例如http
  • Visual C++ 表达式必须具有常量值

    有谁知道为什么 Visual Studio 是唯一给我这个错误的编译器 表达式必须有一个常量值 指大小 include
  • 带有运行时参数的 dlsym/dlopen

    我正在尝试做类似以下的事情 enum types None Bool Short Char Integer Double Long Ptr int main int argc char args enum types params 10 0
  • 禁用iPhone“保存图像”弹出窗口[重复]

    这个问题在这里已经有答案了 我正在尝试禁用 保存图像 对话框在 iPhone 任何 iOS 设备上显示 当用户在 Safari 中时 他们可以将手指放在图像上 然后将该图像直接保存到手机中 他们有办法用 javascript jquery
  • 如何在 Zend Framework 2 中使用 cookie? [关闭]

    很难说出这里问的是什么 这个问题模棱两可 含糊不清 不完整 过于宽泛或言辞激烈 无法以目前的形式合理回答 如需帮助澄清此问题以便重新打开 访问帮助中心 我不明白如何在 ZF2 中使用 cookie 有人可以建议一些带有 set 和 get
  • 如何在 SwiftUI 中的 firebase 查询期间显示加载动画

    我正在使用 SwiftUI 构建一个应用程序 并有一个 ObservableObject 用于查询我的 Firestore 数据库 我的文档相对较大 并且经常需要查询很多文档 因此我想在查询下载数据时加入某种加载指示器 这是我创建的 Obs