我正在尝试解码来自Firebase DataSnapshot的数据,以便可以使用JSONDecoder进行解码。
当我使用URL进行网络请求(获取Data对象)访问时,我可以很好地解码此数据。
然而,我想使用Firebase API直接获取数据,使用observeSingleEvent如此页面所述。
但是,当我这样做时,无法将结果转换为Data对象,我需要使用JSONDecoder。
是否可以使用DataSnapshot进行新样式的JSON解码? 如何做到呢? 我好像无法弄清楚。
我正在尝试解码来自Firebase DataSnapshot的数据,以便可以使用JSONDecoder进行解码。
当我使用URL进行网络请求(获取Data对象)访问时,我可以很好地解码此数据。
然而,我想使用Firebase API直接获取数据,使用observeSingleEvent如此页面所述。
但是,当我这样做时,无法将结果转换为Data对象,我需要使用JSONDecoder。
是否可以使用DataSnapshot进行新样式的JSON解码? 如何做到呢? 我好像无法弄清楚。
我创建了一个名为CodableFirebase的库,它提供了专门针对Firebase设计的Encoders
和Decoders
。
因此,对于上面的示例:
import Firebase
import CodableFirebase
let item: GroceryItem = // here you will create an instance of GroceryItem
let data = try! FirebaseEncoder().encode(item)
Database.database().reference().child("pathToGraceryItem").setValue(data)
以下是如何读取相同数据的方法:
Database.database().reference().child("pathToGraceryItem").observeSingleEvent(of: .value, with: { (snapshot) in
guard let value = snapshot.value else { return }
do {
let item = try FirebaseDecoder().decode(GroceryItem.self, from: value)
print(item)
} catch let error {
print(error)
}
})
我使用JSONDecoder将Firebase快照转换为Data格式的JSON,您的结构体需要符合Decodable或Codable协议。我已经使用SwiftyJSON完成了这个过程,但这个示例使用JSONSerialization,它仍然可以工作。
JSONSnapshotPotatoes {
"name": "Potatoes",
"price": 5,
}
JSONSnapshotChicken {
"name": "Chicken",
"price": 10,
"onSale": true
}
struct GroceryItem: Decodable {
var name: String
var price: Double
var onSale: Bool? //Use optionals for keys that may or may not exist
}
Database.database().reference().child("grocery_item").observeSingleEvent(of: .value, with: { (snapshot) in
guard let value = snapshot.value as? [String: Any] else { return }
do {
let jsonData = try JSONSerialization.data(withJSONObject: value, options: [])
let groceryItem = try JSONDecoder().decode(GroceryItem.self, from: jsonData)
print(groceryItem)
} catch let error {
print(error)
}
})
请注意,如果您的JSON键与可解码结构体不同,您需要使用CodingKeys。例如:JSONSnapshotSpinach {
"title": "Spinach",
"price": 10,
"onSale": true
}
struct GroceryItem: Decodable {
var name: String
var price: Double
var onSale: Bool?
enum CodingKeys: String, CodingKey {
case name = "title"
case price
case onSale
}
}
您可以使用Apple文档此处获取有关此信息的更多信息。
不,Firebase返回的是无法解码的FIRDataSnapshot。但是你可以使用这个结构,它非常简单易懂:
struct GroceryItem {
let key: String
let name: String
let addedByUser: String
let ref: FIRDatabaseReference?
var completed: Bool
init(name: String, addedByUser: String, completed: Bool, key: String = "") {
self.key = key
self.name = name
self.addedByUser = addedByUser
self.completed = completed
self.ref = nil
}
init(snapshot: FIRDataSnapshot) {
key = snapshot.key
let snapshotValue = snapshot.value as! [String: AnyObject]
name = snapshotValue["name"] as! String
addedByUser = snapshotValue["addedByUser"] as! String
completed = snapshotValue["completed"] as! Bool
ref = snapshot.ref
}
func toAnyObject() -> Any {
return [
"name": name,
"addedByUser": addedByUser,
"completed": completed
]
}
}
使用 toAnyObject() 方法保存您的项目:
let groceryItemRef = ref.child("items")
groceryItemRef.setValue(groceryItem.toAnyObject())
来源: https://www.raywenderlich.com/139322/firebase-tutorial-getting-started-2
本文将介绍如何使用Firebase,这是一个由Google提供的云端后端服务。Firebase提供多种功能,包括实时数据库、身份验证和云存储等等。使用Firebase可以极大地简化应用程序的后端开发工作,并且它非常易于集成到现有的应用程序中。
在这个教程中,我们将学习如何设置Firebase项目,添加Firebase到我们的应用程序中,以及如何实现Firebase实时数据库。
toAnyObject() -> Any
函数需要如何更改呢? - Learn2Codeextension DatabaseReference {
func makeSimpleRequest<U: Decodable>(completion: @escaping (U) -> Void) {
self.observeSingleEvent(of: .value, with: { snapshot in
guard let object = snapshot.children.allObjects as? [DataSnapshot] else { return }
let dict = object.compactMap { $0.value as? [String: Any] }
do {
let jsonData = try JSONSerialization.data(withJSONObject: dict, options: [])
let parsedObjects = try JSONDecoder().decode(U.self, from: jsonData)
completion(parsedObjects)
} catch let error {
print(error)
}
})
}
}
并使用
self.refPriceStatistics.child(productId).makeSimpleRequest { (parsedArray: [YourArray]) in
callback(parsedArray)
}
Codable
,可以使用以下解决方案直接解码。无需任何插件。我在Cloud Firestore中使用了这个解决方案。import Firebase
import FirebaseFirestoreSwift
let db = Firestore.firestore()
let query = db.collection("CollectionName")
.whereField("id", isEqualTo: "123")
guard let documents = snapshot?.documents, error == nil else {
return
}
if let document = documents.first {
do {
let decodedData = try document.data(as: ModelClass.self)
// ModelClass a Codable Class
}
catch let error {
//
}
}
extension Collection {
//Designed for use with Dictionary and Array types
var jsonData: Data? {
return try? JSONSerialization.data(withJSONObject: self, options: .prettyPrinted)
}
}
yourRef.observe(.value) { (snapshot) in
guard snapshot.exists(),
let value = snapshot.value as? [String],
let data = value.jsonData else {
return
}
//cast to expected type
do {
let yourNewObject = try JSONDecoder().decode([YourClass].self, from: data)
} catch let decodeError {
print("decodable error")
}
}
extension JSONDecoder {
func decode<T>(_ type: T.Type, from value: Any) throws -> T where T : Decodable {
do {
let data = try JSONSerialization.data(withJSONObject: value, options: .prettyPrinted)
let decoded = try decode(type, from: data)
return decoded
} catch {
throw error
}
}