【问题标题】:Fetch data from Firebase by joining tables in iOS通过在 iOS 中加入表从 Firebase 获取数据
【发布时间】:2016-07-10 02:55:23
【问题描述】:

我正在尝试从两个不同的 Firebase 表中获取数据。这是表的结构:

Post {
    1{
       pImages{
           i1:true
           i2:true
       }
    }
    2{
       pImages{
           i3:true

       }
    }
}
Images{
       i1{
          iUrl : ....
          pId : 1
         }
       i2{
          iUrl :...
          pId : 1
         }
       i3{
         iUrl:....
          pId : 2
         }
 }

我需要检索与 id = 1 的帖子对应的图像。以下是我检索图像的实现:

 func retrieveImagesForPost(postId: String,completion: (result: AnyObject?, error: NSError?)->()){
        var imgArray:[Image]=[]
        let postsRef = self.ref.child("post")
        let imagesRef = self.ref.child("image")
        let postImagesRef = postsRef.child(postId).child("pImages");
        postImagesRef.observeEventType(FIRDataEventType.Value, withBlock: { (snapshot) in
            for item in snapshot.children{
                imagesRef.child(item.key).observeSingleEventOfType(.Value, withBlock: { (snap) in
                    let image = Image(snapshot: snap)
                    print(image)
                    imgArray.append(image)
                })
            }
            print(snapshot.key)
            print("called")
            completion(result:imgArray, error:nil)
        })
    }

但是,问题是我无法将imgArray 中的所有图像发送到completion handler。以下是使用 post id ==1 调用 retrieveImagesForPost 的输出。

pImages
called
<TestProject.Image: 0x7f9551e82000>
<TestProject.Image: 0x7f955466a150>

在调用completion handler 后检索图像。我尝试了dispatch groupssemaphores 方法,如下面的post 所述。但结果还是一样。如何让completion handler 等待从 Firebase 获取所有图像?

【问题讨论】:

    标签: ios firebase firebase-realtime-database completionhandler


    【解决方案1】:

    保持一个计数器,随着每张图片的加载而增加。一旦计数器达到snapshot.children 列表的长度,您就完成并调用您的完成处理程序。

    let postImagesRef = postsRef.child(postId).child("pImages");
    postImagesRef.observeEventType(FIRDataEventType.Value, withBlock: { (snapshot) in
        var counter = 0
        for item in snapshot.children{
            imagesRef.child(item.key).observeSingleEventOfType(.Value, withBlock: { (snap) in
                let image = Image(snapshot: snap)
                print(image)
                imgArray.append(image)
                counter = counter + 1
                if (counter == snapshot.childrenCount) {
                    completion(result:imgArray, error:nil)
                }
            })
        }
    })
    

    您可能应该在上面添加一些错误处理,但通常这种方法是经过尝试和测试的。

    【讨论】:

    • 你的功能如何改变我需要在 Firebase 中加入 3 个节点(关系)
    • if (counter == snapshot.childrenCount) 抛出错误!?
    【解决方案2】:

    这个问题的另一个答案是使用 GCD 的DispatchGroup

    首先您需要使用DispatchGroup 创建一个调度组。在这种情况下,您需要手动告诉小组何时开始使用enter() 以及何时结束使用leave()。然后调度组的notify(queue:execute:) 将在主队列上执行完成处理程序。

    小心!进入和离开的数量必须平衡,否则调度组的 notify 永远不会被调用。

    let dispatchGroup = DispatchGroup()
    
    let postImagesRef = postsRef.child(postId).child("pImages");
    postImagesRef.observeEventType(FIRDataEventType.value, withBlock: { (snapshot) in
        for item in snapshot.children{
            dispatchGroup.enter()
            imagesRef.child(item.key).observeSingleEventOfType(.value, withBlock: { (snap) in
                let image = Image(snapshot: snap)
                print(image)
                imgArray.append(image)
                dispatchGroup.leave()
            })
        }
    })
    
    dispatchGroup.notify(queue: DispatchQueue.main, execute: {
        completion(result: imgArray)
    })
    

    【讨论】:

    • 这比使用计数器要好得多,就像在接受的答案中一样。不过,为了使其正常工作,dispatchGroup 必须在第一个观察块内实例化,并在for 之后通知。进出组是正确的。
    猜你喜欢
    • 2020-04-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-05
    • 1970-01-01
    • 2023-03-24
    • 1970-01-01
    • 2021-10-13
    相关资源
    最近更新 更多