通过在 iOS 中加入表从 Firebase 获取数据
Posted
技术标签:
【中文标题】通过在 iOS 中加入表从 Firebase 获取数据【英文标题】:Fetch data from Firebase by joining tables in iOS 【发布时间】: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 groups
和semaphores
方法,如下面的post 所述。但结果还是一样。如何让completion handler
等待从 Firebase 获取所有图像?
【问题讨论】:
【参考方案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
之后通知。进出组是正确的。以上是关于通过在 iOS 中加入表从 Firebase 获取数据的主要内容,如果未能解决你的问题,请参考以下文章