init() 中的 Swift Array.append 不能与 Firestore (Google Cloud/FIrebase) 结合使用
Posted
技术标签:
【中文标题】init() 中的 Swift Array.append 不能与 Firestore (Google Cloud/FIrebase) 结合使用【英文标题】:Swift Array.append in init() not working in combination with Firestore (Google Cloud/FIrebase) 【发布时间】:2020-04-24 18:13:57 【问题描述】:我已经尝试了我的第一个 SwiftUI 项目。 我只想显示存储在 Firestore (Google Firebase) 中的一些数据。 这是我的代码:
import SwiftUI
import FirebaseFirestore
import FirebaseFirestoreSwift
struct MonsterObj: Identifiable, Equatable, Hashable
var id = UUID()
var name: String
var element: String
var immune: String
var size: String
var twoStarWeakness: String
var threeStarWeakness: String
#if DEBUG
static let exampleMonster = MonsterObj(id: UUID(), name: "Test Monster", element: "Test Element", immun: "Test immun", groesse: "Test groesse", twoStarWeakness: "Test 2 Weakness", threeStarWeakness: "Test3 Weakness")
#endif
class MonsterC: ObservableObject
@Published var monsters = [MonsterObj]()
init()
let db = Firestore.firestore()
var monsterNames: [String] = []
db.collection("Monster").getDocuments() (querySnapshot, err) in
if let err = err
print(err)
else
for document in querySnapshot!.documents
monsterNames.append("\(document.documentID)")
print("document: \(document.documentID)")
for monsterName in monsterNames
print(monsterName)
db.collection("Monster").document(monsterName).getDocument (document, error) in
if let document = document, document.exists
let elementGetter = document.get("element") as! String
let immuneGetter = document.get("immune") as! String
let sizeGetter = document.get("size") as! String
let twoStarWeaknessGetter = document.get("2 star weakness") as! String
let threeStarWeaknessGetter = document.get("3 star weakness")as! String
self.monsters.append(MonsterObj(name: monsterName, element: elementGetter, immune: immuneGetter, size: sizeGetter, twoStarWeakness: twoStarWeaknessGetter, threeStarWeakness: threeStarWeaknessGetter))
这是我的观点:
import SwiftUI
struct ContentView: View
@EnvironmentObject var monsterT: MonsterC
var body: some View
List(monsterT.monsters, id: \.self) monster in
Text(monster.name)
我对 SceneDelegate.swift 做了以下操作:
var window: UIWindow?
var monsterT = MonsterC()
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions
// Create the SwiftUI view that provides the window contents.
let contentView = ContentView().environmentObject(monsterT)
if let windowScene = scene as? UIWindowScene
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView: contentView)
self.window = window
window.makeKeyAndVisible()
所以我的问题是列表是空的。
我在 MonsterC 类的 init
中发现 monsterNames.append("\document.documentID)")
行不会将任何内容附加到 MonsterNames。
但是print("document: \(document.documentID)")
正在打印所有怪物名称。
我的 google Firestore 结构如下所示:
Collection -> Document -> Fields
-------------------------------------------
Monster -> Anjanath -> immune: fire,
element: fire
等等。 只有一个集合(“Monster”)。
谁能向初学者解释为什么 .append
在这里不起作用,但 print 一切正常?
【问题讨论】:
如果您打印print("After monstersNames.append: \monsterNames)")
会不会是因为您缺少异步概念?
【参考方案1】:
您需要了解调用异步函数。我的建议是重构你的代码,在你的 init() 中进行这些异步调用不是一个好主意。
你的函数 "db.collection("Monster").getDocuments() (querySnapshot, err) in ..." 是异步的。您必须等到它完成才能使用结果,或者在函数内执行您需要的操作。请注意,您还有另一个异步函数 "db.collection("Monster").document(monsterName).getDocument "
所以 .append 不起作用,因为执行 .append 时函数“db.collection("Monster").getDocuments() (querySnapshot, err) in ...”的结果不可用。
所以如果你必须使用这个狡猾的代码,试试这个来解决你的数组问题:
class MonsterC: ObservableObject
@Published var monsters = [MonsterObj]()
init()
let db = Firestore.firestore()
db.collection("Monster").getDocuments() (querySnapshot, err) in
if let err = err
print(err)
else
var monsterNames: [String] = []
for document in querySnapshot!.documents
monsterNames.append("\(document.documentID)")
print("document: \(document.documentID)")
for monsterName in monsterNames
print(monsterName)
db.collection("Monster").document(monsterName).getDocument (document, error) in
if let document = document, document.exists
let elementGetter = document.get("element") as! String
let immuneGetter = document.get("immune") as! String
let sizeGetter = document.get("size") as! String
let twoStarWeaknessGetter = document.get("2 star weakness") as! String
let threeStarWeaknessGetter = document.get("3 star weakness")as! String
self.monsters.append(MonsterObj(name: monsterName, element: elementGetter, immune: immuneGetter, size: sizeGetter, twoStarWeakness: twoStarWeaknessGetter, threeStarWeakness: threeStarWeaknessGetter))
【讨论】:
感谢有关异步函数的信息。您称其为“狡猾的代码”,所以我想这样做很糟糕。你能告诉我如何做得更好吗? 很抱歉称代码不可靠。好问题,如何使代码更好。但是,在不了解您要达到的目标的情况下,这超出了我的范围。对我来说 init() 是用于创建/准备类和初始化任何存储的属性。要更新/填充属性,我倾向于在 init() 之外进行,尤其是在涉及异步函数的情况下。类似于带有回调的静态函数 createMonsterClass(...) 以防获取错误。当您在 init() 中执行所有这些操作时,您永远不知道是否存在错误,或者当您想使用它时对象是否已准备好。 由于您已经导入了FirebaseFirestoreSwift
,您可以使用queryDocumentSnapshot.data(as: MonsterObj.self)
使映射更加轻松以上是关于init() 中的 Swift Array.append 不能与 Firestore (Google Cloud/FIrebase) 结合使用的主要内容,如果未能解决你的问题,请参考以下文章
json.swift 错误是 Self.init 在委托初始化程序中的所有路径上都没有调用
init() 中的 Swift Array.append 不能与 Firestore (Google Cloud/FIrebase) 结合使用