swiftfirebasefirebase-realtime-database

Firebase converting snapshot value to objects


So I have a postDict as [String: AnyObject] and I have a model class Post.

Is there a quick way to convert postDict to an array of Post objects so that when dequeuing the cell, it will be:

cell.textLabel.text = posts[indexPath.item].author

import UIKit
import Firebase

class ViewController: UIViewController {

var posts = [Post]()

override func viewDidLoad() {
    super.viewDidLoad()

    let ref = FIRDatabase.database().reference().child("posts").queryLimitedToFirst(5)

    ref.observeEventType(FIRDataEventType.ChildAdded, withBlock: { (snapshot) in
        let postDict = snapshot.value as! [String : AnyObject]

        print(postDict)          

        //convert postDict to array of Post objects
    })
  }
}

class Post: NSObject {
    var author: String = ""
    var body: String = ""
    var imageURL: String = ""
    var uid: String = ""
}

This is the output when printing out postDict:

enter image description here


Solution

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