Swift 4 的 JSONDecoder 可以和 Firebase 实时数据库一起使用吗?
Can Swift 4's JSONDecoder be used with Firebase Realtime Database?
我正在尝试解码来自 Firebase DataSnapshot 的数据,以便可以使用 JSON解码器对其进行解码。
当我使用 URL 通过网络请求访问它(获取数据对象)时,我可以很好地解码该数据。
但是,我想使用 Firebase API 直接获取数据,使用 this page 中描述的 observeSingleEvent。
但是,当我这样做时,我似乎无法将结果转换为数据对象,我需要使用 JSON解码器。
是否可以使用 DataSnapshot 进行新的 JSON 解码?这怎么可能?我似乎无法弄清楚。
没有。 Firebase returns 无法解码的 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
我创建了一个名为 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)
}
})
我使用 JSON解码器将 Firebase 快照转换回数据格式的 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 密钥与您的 Decodable 结构不同。您需要使用 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 文档找到更多相关信息 here。
您可以将 Firebase 返回的值转换为数据,然后对其进行解码。
将此扩展程序添加到您的项目中:
extension Collection {
//Designed for use with Dictionary and Array types
var jsonData: Data? {
return try? JSONSerialization.data(withJSONObject: self, options: .prettyPrinted)
}
}
然后用它把观察到的snapshot的值转化成数据,然后可以解码:
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 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 { [=10=].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)
}
您可以使用此库 CodableFirebase 或以下扩展可能会有帮助。
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
}
}
如果你的数据类型是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 {
//
}
}
我正在尝试解码来自 Firebase DataSnapshot 的数据,以便可以使用 JSON解码器对其进行解码。
当我使用 URL 通过网络请求访问它(获取数据对象)时,我可以很好地解码该数据。
但是,我想使用 Firebase API 直接获取数据,使用 this page 中描述的 observeSingleEvent。
但是,当我这样做时,我似乎无法将结果转换为数据对象,我需要使用 JSON解码器。
是否可以使用 DataSnapshot 进行新的 JSON 解码?这怎么可能?我似乎无法弄清楚。
没有。 Firebase returns 无法解码的 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
我创建了一个名为 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)
}
})
我使用 JSON解码器将 Firebase 快照转换回数据格式的 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 密钥与您的 Decodable 结构不同。您需要使用 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 文档找到更多相关信息 here。
您可以将 Firebase 返回的值转换为数据,然后对其进行解码。
将此扩展程序添加到您的项目中:
extension Collection {
//Designed for use with Dictionary and Array types
var jsonData: Data? {
return try? JSONSerialization.data(withJSONObject: self, options: .prettyPrinted)
}
}
然后用它把观察到的snapshot的值转化成数据,然后可以解码:
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 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 { [=10=].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)
}
您可以使用此库 CodableFirebase 或以下扩展可能会有帮助。
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
}
}
如果你的数据类型是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 {
//
}
}