labnxx labnxx - 4 months ago 83
iOS Question

How to add model data objects to Firebase database

I have 2 questions:


  1. I know how to add regular objects to Firebase using simple key-value pairs but how would I add a user object?

  2. In my UserAccount object I'm not to sure about the UserAcct's second init method. Should I use the init(snapshot: FIRDataSnapshot){} to add to Firebase or should I just stick with the regular init method?



My user model object:

import Foundation
import UIKit
import Firebase
import FirebaseDatabase

class UserAccount{

var userID: String
var email: String
var creationDate: String

init(userID: String, email: String, creationDate: String){

self.userID = userID
self.email = email
self.creationDate = creationDate
}//end init

//Is this second init necessary?
init(snapshot: FIRDataSnapshot) {
userID = snapshot.value!["userID"] as! String
email = snapshot.value!["email"] as! String
creationDate = snapshot.value!["creationDate"] as! String
}

}//END class


My class for signing a user up:

import UIKit
import Firebase
import FirebaseAuth
import FirebaseDatabase

class CreateAccountController: UIViewController{

@IBOutlet weak var emailTextField: UITextField!
@IBOutlet weak var passwordTextField: UITextField!


var dbRef: FIRDatabaseReference!

//Array to hold users
var userAcct = [UserAccount]()


override func viewDidLoad() {
super.viewDidLoad()

//Firebase Ref
self.dbRef = FIRDatabase.database().reference()
}

//Button to sign the user up
@IBAction func signUpButtonPressed(sender: UIButton) {


FIRAuth.auth()?.createUserWithEmail(emailTextField.text!, password: passwordTextField.text!, completion: {

(user, error) in

if error != nil{
print(error?.localizedDescription)
}else{

let emailAddress = self.emailTextField.text!
let currentUserID: String = (FIRAuth.auth()?.currentUser?.uid)!
let accountCreationDate = FIRServerValue.timestamp()

self.userAcct =[UserAccount(userID: currentUserID, email: emailAddress, creationDate: accountCreationDate)]


self.dbRef.child("Users").child("UserID: \(currentUserID)").child("Account-Creation-Date").setValue([\\How to add my self.userAcct model object in here? Should I add it to an array])
}
})
}

Answer

I would suggest you create a protocol like this one:

protocol DictionaryConvertible {
    init?(dict:[String:AnyObject])
    var dict:[String:AnyObject] { get }
}

Note that this is uses an optional initializer, which means that it can fail and return nil. I used this to ensure that all the key-value pairs you need from the dictionary are really there, and return nil otherwise. Now you can add conformance to your UserAccount class like this:

class UserAccount: DictionaryConvertible {

    var userID: String
    var email: String
    var creationDate: String

    init(userID: String, email: String, creationDate: String){
        self.userID = userID
        self.email = email
        self.creationDate = creationDate
    }

    // DictionaryConvertible protocol methods
    required convenience init?(dict: [String:AnyObject]) {
        guard let userID = dict["userID"] as? String, email = dict["email"] as? String, creationDate = dict["creationDate"] as? String else {
            return nil
        }
        self.init(userID: userID, email: email, creationDate: creationDate)
    }
    var dict:[String:AnyObject] {
        return [
            "userID": userID,
            "email": email,
            "creationDate": creationDate
        ]
    }
}

Note: I used the initializer you already made instead to get rid of the boilerplate code. To interact with Firebase simply initialize your UserAccount like this:

let user:UserAccount? = UserAccount(dict: snapshot?.value as! [String:Anyobject])

You can write your object to firebase like this:

ref.child("Users").child(user!.userID).setValue(user!.dict)

What is great about this approach is that is flexible so you can use with any data object simply by adding conformance to the protocol (especially easy when you use structs instead of classes because then you can just add conformance to the protocol using extensions). You could even use this with any kind of database that works with dictionaries without needing to change much. Also, you should make sure all those optionals are dealt with in a safe way and avoid those '!' whenever possible.