Firebase converting snapshot value to objects
Try using the class, protocol and extension I have created below, it will save you a lot of time trying to map the snapshots to objects.
//
// FIRDataObject.swift
//
// Created by Callam Poynter on 24/06/2016.
//
import Firebase
class FIRDataObject: NSObject {
let snapshot: FIRDataSnapshot
var key: String { return snapshot.key }
var ref: FIRDatabaseReference { return snapshot.ref }
required init(snapshot: FIRDataSnapshot) {
self.snapshot = snapshot
super.init()
for child in in snapshot.children.allObjects as? [FIRDataSnapshot] ?? [] {
if respondsToSelector(Selector(child.key)) {
setValue(child.value, forKey: child.key)
}
}
}
}
protocol FIRDatabaseReferenceable {
var ref: FIRDatabaseReference { get }
}
extension FIRDatabaseReferenceable {
var ref: FIRDatabaseReference {
return FIRDatabase.database().reference()
}
}
Now you can create a model that inherits the FIRDataObject class and can be initialised with a FIRDataSnapshot. Then add the FIRDatabaseReferenceable protocol to your ViewController to get access to your base reference.
import Firebase
import UIKit
class ViewController: UIViewController, FIRDatabaseReferenceable {
var posts: [Post] = []
override func viewDidLoad() {
super.viewDidLoad()
ref.child("posts").observeEventType(.ChildAdded, withBlock: {
self.posts.append(Post(snapshot: $0))
})
}
}
class Post: FIRDataObject {
var author: String = ""
var body: String = ""
var imageURL: String = ""
}
UPDATE for Swift 3
class FIRDataObject: NSObject {
let snapshot: FIRDataSnapshot
var key: String { return snapshot.key }
var ref: FIRDatabaseReference { return snapshot.ref }
required init(snapshot: FIRDataSnapshot) {
self.snapshot = snapshot
super.init()
for child in snapshot.children.allObjects as? [FIRDataSnapshot] ?? [] {
if responds(to: Selector(child.key)) {
setValue(child.value, forKey: child.key)
}
}
}
}
Firebase realtime database DataSnapshot value to Object conversion
In your case the constructor that gets called is the parameterless since you are reading from the database using getValue()
, which is required to map the values in the DataSnapshot
. According to the doc, these are the rules you must follow to get the DataSnapshot
data into a custom Java Class:
The class must have a default constructor that takes no arguments
The class must define public getters for the properties to be assigned. Properties without a public getter will be set to their default value when an instance is deserialized.
I you want to set the value for the property fullName
you can do it in the same getFullName()
method. Something like this:
public String getFullName() {
if(fullName == null){// it will be null the first time assuming the value doesn't exist in the database.
fullName = getFirstName() + getLastName();
}
return fullName;
}
Swift 4, Firebase how to observe the snapshot and convert into object
Use the below code to get your required values
guard let uid = Auth.auth().currentUser?.uid else {
return
}
let ref = Database.database().reference().child("users").child("\(uid)")
ref.child("Dream").observe(.value, with: { (snapshot) in
guard let dictionary = snapshot.value as? [String : AnyObject] else {
return
}
print(dictionary["content"] as? String)
}, withCancel: nil)
ref.child("Grocerylist").observe(.value, with: { (snapshot) in
guard let dictionary = snapshot.value as? [String : AnyObject] else {
return
}
print(dictionary["content"] as? String)
}, withCancel: nil)
How to pull snapshot key & values into list through Map ?
In this code you only use the element.value
of each node in your results:
return Items.fromRTDB(Map<String, dynamic>.from(element.value));
If you also want to get the key of each item, you will have to also use element.key
in there and pass that to your Items
object.
Something like this:
Items.fromRTDB(element.key, Map<String, dynamic>.from(element.value));
...
class Items{
final String key;
final String item;
final String expiryDate;
final String quantity;
final String user;
Items({required this.key, required this.item, required this.expiryDate, required this.quantity, required this.user});
//Mapping from real-time database
factory Items.fromRTDB(String key, Map<String, dynamic> data) {
return Items(
key: key,
item: data['item'],
expiryDate: data['exp'],
quantity: data['qty'],
user: data['user'],
);
}
}
Converting DataSnapshot to custom struct object - Swift 4
Managed to solve the problem using a workaround:
This code goes before the viewDidLoad()
method of your ViewController
let ref = Database.database().reference().child("alldata")
var companyName: [String] = []
var maxCm: [String] = []
var maxIn: [String] = []
var weightKg: [Int] = []
var weightLb: [Int] = []
And in the viewDidLoad()
override func viewDidLoad() {
super.viewDidLoad()
ref.queryOrderedByKey().observeSingleEvent(of: .value) { (snapshot) in
let snapshotValue = snapshot.value as! [String:[String:AnyObject]]
let sorted = snapshotValue.sorted() { $0.key.lowercased() < $1.key.lowercased() }
for (key, _) in sorted {
let keys = snapshotValue[key]
let company_name = key
self.companyName.append(company_name)
let carry_max_cm = keys?["keyname"] as! String
self.maxCm.append(carry_max_cm)
let carry_max_in = keys?["keyname"] as! String
self.maxIn.append(carry_max_in)
let carry_weight_kg = keys?["keyname"] as! Int
self.weightKg.append(carry_weight_kg)
let carry_weight_lb = keys?["keyname"] as! Int
self.weightLb.append(carry_weight_lb)
}
self.tableView.reloadData()
}
}
let sorted = snapshotValue.sorted() { $0.key.lowercased() < $1.key.lowercased() }
Orders the dictionary alphabetically
Casting an Object as a Map when Firebase RTDB is updated
Due to changes in version 9 from dynamic to object, you can define the snapshot value as dynamic:
final event = await resp.once();
_usuario = UsuarioModel.fromJson(Map<String, dynamic>.from(event.snapshot.value as dynamic));
It's a workaround, but it does work!
Related Topics
Whats the Swift Animate Withduration Syntax
How to Check Two Instances Are the Same Class/Type in Swift
Swift - Increment Label With Stepper in Tableview Cell
Swift 5: What's 'Escaping Closure Captures Mutating 'Self' Parameter' and How to Fix It
Reference to Property in Closure Requires Explicit 'Self.' to Make Capture Semantics Explicit
Why .Pch File Not Available in Swift
Why Are Doubles Printed Differently in Dictionaries
Swift - Custom Setter on Property
Why Is the Shorthand Argument Name $0 Returning a Tuple of All Parameters
Swift: Failing to Copy Files to a Newly Created Folder
Convert Between Decimal, Binary and Hexadecimal in Swift
How to Include .Swift File from Other .Swift File in an Immediate Mode
Sort Array by Calculated Distance in Swift
Ambiguous Reference to Member 'Tableview'
How to Get the File Creation Date Using Url Resourcevalues Method in Swift 3