获取 Firebase 文档对象作为 Swift 对象

tom*_*lum 2 ios firebase swift google-cloud-firestore

我尝试为 iOS 实现一个简单的购物清单 swift 应用程序作为个人项目。我确实在youtube上遵循了 iOS 指南。

我的问题是如何将Item对象从 firebase解析为我的ShoppingListItemswift 对象?如果我执行以下代码,它不会显示任何错误消息,但也不会显示任何结果。如果我取消注释所有“项目”行,它会显示没有项目信息的预期结果。

这是我的firebase firestore 结构/示例对象的 firebase 控制台的屏幕截图

提前致谢!


ShoppingListItem.swift

import Foundation
import FirebaseFirestore

protocol DocumentSerializable {
    init?(dictionary: [String: Any])
}

struct ShoppingListItem {
    var shoppingItemID: String
    var priority: Int
    var quantity: Int
    var item: Item

    var dictionary: [String: Any] {
        return [
            "shoppingItemID": shoppingItemID,
            "priority": priority,
            "quantity": quantity,
            "item": item,
        ]
    }
}

extension ShoppingListItem: DocumentSerializable {

    init?(dictionary: [String : Any]) {
        guard let shoppingItemID = dictionary["shoppingItemID"] as? String,
            let priority = dictionary["priority"] as? Int,
            let quantity = dictionary["quantity"] as? Int,
            let item = dictionary["item"] as? Item
        else { return nil }


        self.init(shoppingItemID: shoppingItemID, priority: priority, quantity: quantity, item: item)
    }
}

struct Item {

    var itemID: String
    var lastPurchase: String
    var name: String
    var note: String
    var picturePath: String

    var dictionary: [String: Any] {
        return [
            "itemID": itemID,
            "lastPurchase": lastPurchase,
            "name": name,
            "note": note,
            "picturePath": picturePath,
        ]
    }
}

extension Item: DocumentSerializable {

    init?(dictionary: [String : Any]) {
        guard let itemID = dictionary["itemID"] as? String,
            let lastPurchase = dictionary["lastPurchase"] as? String,
            let name = dictionary["name"] as? String,
            let note = dictionary["note"] as? String,
            let picturePath = dictionary["picturePath"] as? String else { return nil }

        self.init(itemID: itemID, lastPurchase: lastPurchase, name: name, note: note, picturePath: picturePath)
    }
}
Run Code Online (Sandbox Code Playgroud)

在 TableViewController.swift 中获取数据调用

        db.collection("shoppingList").getDocuments(){
            querySnapshot, error in

            if let error = error {
                print("error loading documents \(error.localizedDescription)")
            } else{
                self.shoppingArray = querySnapshot!.documents.flatMap({ShoppingListItem(dictionary: $0.data())})

                DispatchQueue.main.async {
                    self.tableView.reloadData()
                }
            }

        }
Run Code Online (Sandbox Code Playgroud)

AgR*_*zzo 6

我使用了 Codable 协议。

我将其用作可编码协议的扩展:

extension Encodable {
  /// Returns a JSON dictionary, with choice of minimal information
  func getDictionary() -> [String: Any]? {
    let encoder = JSONEncoder()

    guard let data = try? encoder.encode(self) else { return nil }
    return (try? JSONSerialization.jsonObject(with: data, options: .allowFragments)).flatMap { $0 as? [String: Any]
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

然后我用它来解码:

extension Decodable {
  /// Initialize from JSON Dictionary. Return nil on failure
  init?(dictionary value: [String:Any]){

    guard JSONSerialization.isValidJSONObject(value) else { return nil }
    guard let jsonData = try? JSONSerialization.data(withJSONObject: value, options: []) else { return nil }

    guard let newValue = try? JSONDecoder().decode(Self.self, from: jsonData) else { return nil }
    self = newValue
  }
}
Run Code Online (Sandbox Code Playgroud)

使您的两个结构符合 Codable(首先是 Item,然后是 ShoppingListItem)。当然,这可能不适用于 Firestore 中存储的现有数据。我会首先通过getDictionary()(在一个新集合中)将数据放入 Firestore ,然后尝试将其读回您的 tableView。