将Firebase文档对象作为Swift对象

时间:2018-03-03 17:08:41

标签: ios swift firebase google-cloud-firestore

我尝试将iOS的简单购物清单swift应用程序实现为个人项目。我确实按照youtube上的iOS指南进行了操作。

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

以下是我firebase firestore structure / example object

的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)
    }
}

在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()
                }
            }

        }

1 个答案:

答案 0 :(得分:2)

我使用了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]
    }
  }
}

然后我用它来解码:

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
  }
}

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