我尝试将iOS的简单购物清单swift应用程序实现为个人项目。我确实按照youtube上的iOS指南进行了操作。
我的问题是如何解析firebase中的Item
对象到我的ShoppingListItem
swift对象?如果我执行以下代码,它不会显示任何错误消息,但它也不会显示任何结果。如果我取消注释所有"项目"行,它显示没有项目信息的预期结果。
以下是我firebase firestore structure / example object
的firebase控制台的屏幕截图提前致谢!
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)
}
}
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()
}
}
}
答案 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中。