我正在尝试从 Firebase 实时数据库检索数据。我可以在 Firebase 控制台中看到数据,但在我的应用程序中看不到数据。
这是数据库的结构:
用户 -> someUserIDs -> items -> someItemIDs ->detailsOfTheItem。
在我的 DatabaseManager 类中:
static var shared = DatabaseManager()
private let databaseRef = Database.database().reference()
func saveItem(_ item: InventoryItem, path: String) {
let itemRef = databaseRef.child(path).child(item.id)
itemRef.setValue(item.dictionaryRepresentation())
}
func fetchItems(path: String, completion: @escaping ([InventoryItem]) -> ()) {
let itemsRef = databaseRef.child(path)
itemsRef.observeSingleEvent(of: .value, with: { (snapshot) in
guard let value = snapshot.value as? [String: Any] else {
print("No items data found")
completion([])
return
}
var items = [InventoryItem]()
for (_, itemData) in value {
guard let itemDict = itemData as? [String: Any],
let itemID = itemDict["itemID"] as? String,
let name = itemDict["name"] as? String,
let itemPrice = itemDict["itemPrice"] as? Double,
let itemQuantity = itemDict["itemQuantity"] as? Int,
let size = itemDict["size"] as? String,
let AdditionDateTimestamp = itemDict["AdditionDate"] as? Double,
let itemNotes = itemDict["itemNotes"] as? String
else {
continue
}
let AdditionDate = Date(timeIntervalSince1970: AdditionDateTimestamp)
let item = InventoryItem(
itemID: itemID,
name: name,
itemPrice: itemPrice,
itemQuantity: itemQuantity,
size: size,
AdditionDate: AdditionDate,
itemNotes: itemNotes
)
items.append(item)
}
completion(items)
})
}
在我的 InventoryManager 类中,我正在保存并获取这样的数据:
class InventoryManager: ObservableObject {
static var shared = InventoryManager()
@Published var items: [InventoryItem] = []
private var isUserSignedIn = Auth.auth().currentUser != nil
func fetchItemsFromDB() {
if let currentUser = Auth.auth().currentUser {
let userID = currentUser.uid
print("Current UserID: \(userID)")
let path = "users/\(userID)/items"
DatabaseManager.shared.fetchItems(path: path, completion: { fetchedItems in
self.items = fetchedItems
})
}
}
func saveItem2DB(_ item: InventoryItem) {
if let currentUser = Auth.auth().currentUser {
let userID = currentUser.uid
let path = "users/\(userID)/items"
DatabaseManager.shared.saveItem(item, path: path)
}
}
func addItem(item: InventoryItem) {
items.append(item)
if isUserSignedIn{
saveItem2DB(item)
}
else{
saveItems2UD()
}
}
我在ContentView中初始化并将其显示在InventoryContentView中。当我使用 UserDefaults 时它工作得很好,但当我添加实时数据库时它却不起作用。
struct ContentView: View {
@StateObject private var inventoryManager = InventoryManager.shared
@State private var isUserSignedIn = Auth.auth().currentUser != nil
init() {
if isUserSignedIn {
InventoryManager.shared.fetchItemsFromDB()
}
else {
InventoryManager.shared.loadItemsFromUD()
}
}
...
}
struct InventoryContentView: View {
@ObservedObject var inventoryManager: InventoryManager
...
var filteredItems: [InventoryItem] {
if searchText.isEmpty {
return Array(inventoryManager.getItems())
} else {
return Array(inventoryManager.getItems().filter { $0.name.lowercased().contains(searchText.lowercased()) })
}
}
var body: some View {
...
if inventoryItems.isEmpty {
Text("No inventory items yet")
.font(.headline)
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
else
{
List(sortedItems) { item in // sortedItems gets its data from filteredItems
NavigationLink(destination: ItemDetailsView(inventoryManager: inventoryManager, item: item))
{
VStack(alignment: .leading) {
Text("Name: \(item.name)")
Text("Price: \(item.itemPrice, specifier: "%.2f")")
Text("Q: \(item.itemQuantity)")
}
}
...
}
var inventoryItems: [InventoryItem] {
return inventoryManager.items
}
}
根据您的评论:
好像叫
else { continue }
您需要调试:使用断点或添加打印,看看您的应用程序运行时到底去了哪里。
好像你输入了大中的
continue
:
guard let ... else { continue }
让我们修改它以确保情况确实如此:
guard let ... else {
print("Didn't pass the guard let, will continue")
continue
}
现在,让我们分析一下您的
guard let
:
let itemID = itemDict["itemID"] as? String
这意味着
let itemID
将是 nil
,然后在以下情况下您将输入 else
的 guard let
:
itemDict["itemID"]
是 nil
或 itemDict["itemID"]
不是 nil
,但不是 String
。
您有 7 个
nil
测试,以及 8 个石膏测试 (as?
)。因此,在这里,您可能有 15 个可能的理由来点击 else
(continue
)。
guard let itemDict = itemData as? [String: Any],
let itemID = itemDict["itemID"] as? String,
let name = itemDict["name"] as? String,
let itemPrice = itemDict["itemPrice"] as? Double,
let itemQuantity = itemDict["itemQuantity"] as? Int,
let size = itemDict["size"] as? String,
let AdditionDateTimestamp = itemDict["AdditionDate"] as? Double,
let itemNotes = itemDict["itemNotes"] as? String
else {
continue
}
那么让我们开始调试是哪一个导致了问题。
如果您使用断点,请在控制台中执行以下操作:
po itemDict["itemID"] as? String
如果是
nil
,那就做
po itemDict["itemID"]
如果是
nil
,则表示该值不存在(密钥错误?可以为nil吗?),如果不是,则表示强制转换(as? String
)不起作用。所以这不是String
。
对每一个都做同样的事情,找到一个或多个罪魁祸首。
仅打印:
print("itemDict[\"itemID\"]: \(itemDict["itemID"])")
print("itemDict[\"itemID\"] as? String: \(itemDict["itemID"] as? String)")
... //Do all of them
看看哪一个是
nil
,与之前的 po
的推理相同。
并找出为什么其中一个值是
nil
。我们不知道您的 Firebase 型号,因此无法猜测。
如果转换失败,请检查您的模型实际上属于哪个类别,请参阅修改您的 iOS 模型,或者在将其设置到您的模型之前如果不能转换该值(例如,如果您的 Firebase 模型返回
Int
但您它可以用作 String
,然后将该整数转换为字符串(如果这对您的应用程序有意义)。