Firebase Swift 3 Xcode 8 - 迭代观察结果

时间:2023-01-23 17:10:48

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.

我查看了Firebase上的文档以及Stack Overflow和YouTube教程,但是如果通过Firebase获取,我可以了解如何获取数据。

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

我是Firebase的新手,也是我将项目从Parse切换到Firebase的过程。

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

示例:我在Firebase中有一个如下所示的数据:

Firebase Swift 3 Xcode 8  - 迭代观察结果

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

我可以抓住Swift中的所有主题:

 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:

当我遍历for循环时,我会打印出如下所示的内容:

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

我需要密钥(KYCqk2_AVkUd8s9cKiu)我需要描述和名称我需要一个标签数组

-- 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.

我可以负责构建Class主题的数组,但我已经尝试了几种方法来获取数据而没有运气。必须有一种简单的方法来解析结果,但我没有找到示例或文档。

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.

FDataSnapshot未定义,因此我使用了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)

...在这里打破三次,然后应用程序崩溃在这一行让dict = snap.value为! [String:String],消息“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]

我不确定为什么代码有断点以及它崩溃的原因。点击标签时可能会崩溃,因为标签是子节点并且不适合[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.

我从其他响应发送的doc链接中找出了主题密钥。谢谢。

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.

我不确定我是否正确获取了标签值。它实际上只是一个字典而且我试图以这种方式进行转换,但是运行时崩溃并希望将标签转换为NSArray ....所以我在代码中执行了它并且它可以工作但不确定这是否安全,因为这不是定义为数组,即使它作为数组返回。

3 个解决方案

#1


5  

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.

也可以使用child.key找到每个子节点的父节点名称。

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.

典型的设计模式是利用类数组(或dicts或结构等)作为tableView的dataSource。您将遍历子项并为每个子项创建一个类,并将其附加到tableView。完成后,tableView.reloadData更新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.

同样重要的是要记住Firebase是异步的,因此不要尝试在Observe闭包之外访问或使用该数组,直到其中的代码完成。

#2


1  

FIRDataSnapshot's value property returns the contents of the snapshot as a standard Foundation type.

FIRDataSnapshot的value属性将快照的内容作为标准Foundation类型返回。

#3


0  

You could do it the easy way with my SnapshotParser.

你可以用我的SnapshotParser轻松实现。

You would need the following code to get a swift representation:

您需要以下代码才能获得快速表示:

func main(){
    let topics=SnapshotParser().parseAsList(snap: Snapshot, type: Topic.self)
    for topic in topics{
        //do something with your object
    }
}

class Topic: ParsableSnapshot {
    var id:String?=nil
    var createdBy:String?=nil
    var description:String?=nil
    var name:String?=nil
    var tags:[Int:String]?=nil

    required init(){}

    func bindProperties(binder: SnapshotParser.Binder) {
        binder.bindField(name: "id", field: &id)
        binder.bindField(name: "createdBy", field: &createdBy)
        binder.bindField(name: "description", field: &description)
        binder.bindField(name: "name", field: &name)
        binder.bindDictionary(name: "tags", dict: &tags)
    }
}

#1


5  

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.

也可以使用child.key找到每个子节点的父节点名称。

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.

典型的设计模式是利用类数组(或dicts或结构等)作为tableView的dataSource。您将遍历子项并为每个子项创建一个类,并将其附加到tableView。完成后,tableView.reloadData更新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.

同样重要的是要记住Firebase是异步的,因此不要尝试在Observe闭包之外访问或使用该数组,直到其中的代码完成。

#2


1  

FIRDataSnapshot's value property returns the contents of the snapshot as a standard Foundation type.

FIRDataSnapshot的value属性将快照的内容作为标准Foundation类型返回。

#3


0  

You could do it the easy way with my SnapshotParser.

你可以用我的SnapshotParser轻松实现。

You would need the following code to get a swift representation:

您需要以下代码才能获得快速表示:

func main(){
    let topics=SnapshotParser().parseAsList(snap: Snapshot, type: Topic.self)
    for topic in topics{
        //do something with your object
    }
}

class Topic: ParsableSnapshot {
    var id:String?=nil
    var createdBy:String?=nil
    var description:String?=nil
    var name:String?=nil
    var tags:[Int:String]?=nil

    required init(){}

    func bindProperties(binder: SnapshotParser.Binder) {
        binder.bindField(name: "id", field: &id)
        binder.bindField(name: "createdBy", field: &createdBy)
        binder.bindField(name: "description", field: &description)
        binder.bindField(name: "name", field: &name)
        binder.bindDictionary(name: "tags", dict: &tags)
    }
}