Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Firebase Swift 3 Xcode 8 - iterate through observe results

I have looked through the docs on Firebase and through Stack Overflow and YouTube tutorials, but I can find out how to get at the data if fetch through Firebase.

I am new to Firebase and an in the process of switching my project from Parse to Firebase.

Example: I have a data in Firebase that looks like this:

Topics as seen in Firebase

I can grab all of the topics in Swift doing this:

 let refDB  = FIRDatabase.database().reference(fromURL: firebaseDB_URL)
    let topicsRef = refDB.child("topics")
    // FIRDataSnapshot.
    topicsRef.observe(.value, with: { snapshot in
        for child in snapshot.children {
            print("child ------")
            print(child)
            // Get the bits  HOW DO I PARSE EACH SET

        }
    })

When I iterate through the for-loop, I print things that look like this:

child ------
Snap (-KYCqk2_AVkUd8s9cKit) {
    createdBy = FeMFeeDat4VZb5tmFO2tKixgQIy1;
    description = "Match states with their capitals";
    name = "State Caiptals";
    tags =     {
        0 = Geography;
        1 = USA;
    };
}

child ------
Snap (-KYCqk2_AVkUd8s9cKiu) {
    createdBy = FeMFeeDat4VZb5tmFO2tKixgQIy1;
    description = "Name the parts of an Atom";
    name = "Parts of an Antom";
    tags =     {
        0 = Physics;
        1 = Atom;
        2 = Electron;
    };
}

My problem is, how do I get at the data:

I need the key (KYCqk2_AVkUd8s9cKiu) I need the description and name I need an array of tags

-- all in local variables?

Basically, I just want to read in all the Topics and have an array of Topics in local memory.

I can take care of building the array of Class topic, but I have tried several approaches to getting at the data with no luck. There must be an easy way to parse the result, but I have not found an example or documentation.

Would appreciate some help or pointer to some doc or tutorial.

=================================

Updated Code

Hi I changed code to try to match sample provided. Code now looks like below I put in a loop counter to see what is happening and why crashing.

FDataSnapshot is not defined so I used FIRDataSnapshot.

Here is new attempt at code that now crashes. Further below I show my changes to make it not crash - and a question about handing the tags subnode safely. Thanks for the pointer. I now have something that works.

// HERE is a way to get all the Topics
let refDB  = FIRDatabase.database().reference(fromURL: firebaseDB_URL)
let topicsRef = refDB.child("topics")
// FIRDataSnapshot.
topicsRef.observe(.value, with: { snapshot in

    if snapshot.value is NSNull {
        print("not found")
    } else {
        var loopCount = 1  //  count loops to see how may time trying to loop
        for child in snapshot.children {

            print("            ")
            print("            ")
            print("child ------ loop \(loopCount)")
            print(child)

            let snap = child as! FIRDataSnapshot //each child is a snapshot
            let dict = snap.value as! [String: String] // the value is a dictionary
            let name = dict["name"]!
            let description = dict["description"]!
            let createdBy = dict["createdBy"]!
            print("the bits ------")
            print("name .... \(name)")
            print("description .... \(description)")
            print("createdBy .... \(createdBy)")
            loopCount += 1

        }
    }
})

I have zero breakpoints defined -- however the code stops on this breakpoint (when i have zero breakpoints defined for sure)

libswiftCore.dylib`_swift_bridgeNonVerbatimFromObjectiveC:
    0x1144a4270 <+0>:   pushq  %rbp
    0x1144a4271 <+1>:   movq   %rsp, %rbp
    0x1144a4274 <+4>:   pushq  %r15

... breaks here three times and then the app crashes on this line let dict = snap.value as! [String: String] with message "Thread 1: EXC_BAD_INSTRUCTION (code=EXEC_1386_INVOP, subside=0x0)

I am not sure why the code has breakpoint and why it crashes. Maybe crashed when hits tags because tags is sub node and does not fit [String, String]

I print this in the log and then go boom!!!

child ------ loop 1
Snap (-KYI2MszjC9pK_4oIvKu) {
    createdBy = FeMFeeDat4VZb5tmFO2tKixgQIy1;
    description = "Match states with their capitals";
    name = "State Caiptals";
    tags =     {
        0 = Geography;
        1 = USA;
    };
}

=====

If I change the line to use 'Any' .... then it works

let dict = snap.value as! [String: Any]

new working code ....

// HERE is a way to get all the Topics
let refDB  = FIRDatabase.database().reference(fromURL: firebaseDB_URL)
let topicsRef = refDB.child("topics")
// FIRDataSnapshot.
topicsRef.observe(.value, with: { snapshot in

    if snapshot.value is NSNull {
        print("not found")
    } else {
        var loopCount = 1  //  count loops to see how may time trying to loop
        for child in snapshot.children {

            print("            ")
            print("            ")
            print("child ------ loop \(loopCount)")

            let snap = child as! FIRDataSnapshot //each child is a snapshot

            if snap.value != nil {
                print("key ... \(snap.key)")
                let dict = snap.value as! [String: Any] // the value is a dictionary
                let name = dict["name"] as! String
                let description = dict["description"] as! String
                let createdBy = dict["createdBy"] as! String
                let tags = dict["tags"] as! NSArray  

                /* Thought I could loop tags as! Dictionary but that does not work. Compiles but runtime crashes.
                var tagsArray = [String]()
                if tags != nil && tags.count > 0 {
                    for (key, value) in tags {
                        tagsArray.append(value)
                    }
                } */

                // Test to see what we got ...
                print("the bits ------")
                print("name .... \(name)")
                print("description .... \(description)")
                print("createdBy .... \(createdBy)")
                print("tags ... \(tags)  ... count \(tags.count)")
                loopCount += 1
            } else {
                print("bad snap")
            }

        }
    }
})

I figured out the topic key from the doc link sent by other response. Thanks.

I am not sure I am getting the tag values correctly. It is really just a Dictionary and I tried to cast it that way but runtime crashes and wants to cast tags to an NSArray .... so I did that in the code and it works but not sure if that is safe since this is not defined as an array even though it is coming back as an array.

like image 209
john Avatar asked Dec 05 '16 18:12

john


1 Answers

It's all about dictionaries really.

Given an example node

people_foods
  -Yinasdjasjd
     name: "Leroy"
     food: "Pizza"
  -Yk9j9s9soks
     name: "Pete"
     food: "Wings"

This code gets the data as a snapshot and iterates over it to print the person and their food.

    let ref = self.myRootRef.child(byAppendingPath: "people_foods")!

    ref.observe(.value, with: { snapshot in

        if ( snapshot!.value is NSNull ) {
            print("not found")
        } else {

            for child in (snapshot?.children)! {

                let snap = child as! FDataSnapshot //each child is a snapshot

                let dict = snap.value as! [String: String] // the value is a dict

                let name = dict["name"]
                let food = dict["food"]

                print("\(name) loves \(food)")
            }

        }
    })

The parent node name(s) of each child can be found with child.key as well.

A typical design pattern is to leverage an array of classes (or dicts or structs etc) as the dataSource for a tableView. You would iterate over the children and creates a class for each one and append that to the tableView. When complete, tableView.reloadData to update the UI.

It's also important to remember that Firebase is asynchronous so don't try to access or work with that array outside the Observe closure until the code in it completes.

like image 97
Jay Avatar answered Oct 24 '22 10:10

Jay