通过在iOS中加入表格从Firebase提取数据

问题描述:

我试图从两个不同的Firebase表格中提取数据。下面是表的结构:我需要检索相应的发布与ID = 1。以下是我实施检索图像图像通过在iOS中加入表格从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 
     } 
} 

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。以下是调用retrieveImagesForPost后的输出id = 1。

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

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

保留一个随着每个图像加载而增加的计数器。一旦计数器达到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) 
      } 
     }) 
    } 
}) 

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

+0

请问你的功能变化,我会需要火力地堡 – Learn2Code

+0

加入3个节点(关系),如果(反== snapshot.childrenCount)抛出一个错误!? – Learn2Code

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

首先,您需要创建一个包含DispatchGroup的调度组。在这种情况下,您需要通过enter()以及leave()完成工作时手动通知组。然后调度组的notify(queue:execute:)将在主队列上执行完成处理程序。

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

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) 
}) 
+0

这比使用计数器好得多,就像在公认的答案中一样。尽管为了正常工作,'dispatchGroup'必须在第一个观察块内实例化,并在'for'之后通知。进入和离开组是正确的。 –