swift - 从实时数据库检索数据失败

问题描述 投票:0回答:1

我正在尝试从 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
    }
    
}
swift firebase firebase-realtime-database
1个回答
0
投票

根据您的评论:

好像叫

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
,然后将该整数转换为字符串(如果这对您的应用程序有意义)。

© www.soinside.com 2019 - 2024. All rights reserved.