Firebase is really powerful tool, it enables you to create observer patterns in a declarative way and without any boilerplate code. And recently, I have a great opportunity to migrate existing project to the Firebase and I want to share with you how it happens on practice. This topic is quite a wide so I tried to divide it to several parts from simpler to more complicated.
Let’s dive into the simpler part.

1. Create new iOS project
2. Create new project in the Firebase console
3. Connect to the Firebase DB
4. Create first collections
5. Try add / update / delete queries
6. Create Observers and data sync
7. Working with DateTime types
8. Last but not the least – rules

Create a new iOS project

A good starting point is to create new iOS project. Just run Xcode and create new one. But before we proceed it would be better to install required libraries using cocoapods as dependency manager.

I’m sure you’re familiar with this dance already, however if you haven’t experience with Pods before please check official site and tutorials:

Let’s add ‘Firebase/Database’ library to the Podfile it would be enough for now.
pod 'Firebase/Database'
Btw, if you want to get more info about Firebase libs check this link

Create new project in the Firebase console

Now let’s turn to Google Firebase. To create a new project just go here and don’t forget to choose “Add Firebase to your iOS app”.
create_db
choose_ios_marked

The important thing here is to get the GoogleService.plist configuration file for your iOS project.

steps_marked
After downloading the file, keep it somewhere, we will need it soon. If you missed this step, you can download .plist from project settings at any time.
GS_small_marked

Connect to the Firebase DB

Now we need to go back our iOS project and connect to Firebase by putting on GoogleService.plist to the project Resources folder.
put_GA_to_app
After this, check if you made a connection to the new database in AppDelegateFIRApp.configure().
Otherwise, you will get an error: Terminating app due to uncaught exception 'MissingDatabaseURL', reason: 'Failed to get FIRDatabase instance: FIRApp object has no databaseURL in its FirebaseOptions object.

And of course, please do not forget to put import Firebase.

Create first collections

Firebase based on NoSQL paradigm and if I’m not mistaken it uses MongoDB behind the scene, which requires quite a bit of providence. The more important thing you need to remember is how you are going to manipulate with data. The best way is to use nested data poorly and to focus on flatten data.

Pay attention that you haven’t an opportunity to see the db scheme at once. Usually Firebase creates collections dynamically as soon as first value appears.
animation_in_work_marked

On the off-chance, I provided several ways to come over this:
– Import already prepared json if you have such
– Add each collection and data manually
– Create collections dynamically

Ok, let’s start from dynamically creation of collections. Maybe it seems a bit scary, but It’s actually pretty simple. So, to work with our DB in the iOS app we need the basic building block that contains 4 classes(listed below) and enum called PostKeys:
FIRManager – DB configuration
Post – DataModel
PostsService – To store all queries
ObservePostManager – Interlayer for PostsService

I guess it would be better to show you simple “NoUML” scheme. Notice, the basic building block is circled with orange and the enum is colored by yellow:
no_uml

The enum PostKeys plays a significant role. It reflects the Post’s collection structure.

enum PostKeys: String {
    case PostID      = "PostID"
    case PosterID    = "PosterID"
    case Message     = "Message"
    case PostDate    = "PostDate"
    case IsPublished = "IsPublished"
}

FIRManager class allows us to initialize DB connection and define references to collections.

var rootRef = FIRDatabaseReference.init()
var postsRef = FIRDatabaseReference.init()

func initialize() -> FIRManager {
   rootRef = FIRDatabase.database().reference() // define the root ref of DB
   postsRef = rootRef.child("posts")            // define the ref on collection  
   return self
}

Post is the DataModel class. The main goal to initialize object after getting data and convert them to appropriate view.

var postID: String!       // Unique ID of Post
var posterID: String!     // User ID
let message: String!       // Message
let postDate: AnyObject! // The time when the post was created
let isPublished: Int!    // The published status of post
var ref: FIRDatabaseReference? // Will be the direct reference to object in DB, so you can easy get an access to it

// Initialize object with DB data
init(snapshot: FIRDataSnapshot) {
    postID = snapshot.key
        // ...
    ref = snapshot.ref
}

// Initialize object for pushing to DB
init (message: String) {
    self.postID = nil
       // ...
    self.ref = nil
}

As I mentioned before PostsService stores all necessary queries. ObservePostManager serves the first one and handles all possible errors and data result.

Try add / update / delete queries

After finishing with initializing let’s proceed with queries.
To create new post we must care about uniqueID. To achieve that we need to use next childByAutoId().

class func createNewPost(message: String, completion: (post: Post?) -> Void) {
    let post = Post(message: message)
    firManager?.postRef
     .childByAutoId()
     .setValue(post.toAnyObject()) { error, fb in
      
       if error == nil {
             post.postID = fb.key // setup ID
             post.ref = fb        // setup reference to the object in DB
             completion(post: post)
       } else {
             completion(post: nil)
       }
}

animation_add_marked

For updating of object you can use directly the ref – reference of this object in DB, that’s why we defined this value var ref: FIRDatabaseReference? in DataModel class. In my opinion, it is really cool fancy tool🐥.

So, let’s update our object. Just imagine that we created post which is not published yet and we are going to publish it using the following code:

class func publishPost(post: Post?, isPublish: Int) {
   // Btw, you shouldn’t use all fields, only which you need exactly
   let dic = [PostKeys.IsPublished.rawValue: isPublish] 
   post?.ref!.updateChildValues(dic as [NSObject : AnyObject])
}

animation_update_marked_no_flicker

And the last one is delete. Nothing special just use the ref as we did before.

class func removePost(post: Post) {
post.ref?.removeValue()
}

animation_del_marked

Create Observers and data sync

Now I am going to describe a really cool feature – observers. Observer is probably the most common scheduler operator you’ll use. Observers allow us to track DataModel changes without making special queries, which we used to write before. Let’s quickly investigate observeEventType it might prove its usefulness.

class func getPosts(completion: (postsArray: [Post]) -> Void)  {
    firManager?.postsRef
     .observeEventType(.Value, withBlock: {
       snapshot in
          // ...
       }, withCancelBlock: { error in
          // ...
     })
}

As you can see we created the query for getting post list, however, the key-words are observeEventType and Value.
ObserveEventType – means that we are going to track it
Value – means that we observe all value changes in what we try to observe (creating, removing, updating and so on…)

Sometimes we don’t need to observe child nodes and of course we can skip it. Decide yourself which ones you want to emit and which ones to skip.
observer types

Working with DateTime types

Additionally I would like to show you one of the possible ways to store DateTime values:

let postDate: AnyObject! // Use AnyObject type in Data Model
self.postDate = FIRServerValue.timestamp()  // to pack object for pushing into DB
postDate = snapshot.value![PostKeys.PostDate.rawValue] as! NSTimeInterval // to unpack object from DB

Last but not the least – rules

We will consider the rules in the following articles in details, but the only cryptic thing here that we need to change is default security rules.
rules
Replace them to this one { "rules": { ".read": true, ".write": true } }
Because, as soon as you try to execute any db query, you will get an error:
[FirebaseDatabase] setValue: or removeValue: at /post/POST_ID failed: permission_denied

Firebase is very simple and powerful service. And of course, there are a lot of things that I’ve not mentioned, but I hope my article will help to go through the basics.

You can read more about firebase at codelabs , guidelines and quickstart tutorials. Also if you have some questions, do not hesitate to ask me link or put your comments, I will be happy to help you.

All code samples you can find on GitHub