triple.s triple.s - 4 months ago 25
iOS Question

Fetch data from Firebase by joining tables in iOS

I am trying to fetch data from two different Firebase tables. Here is the structure of table:

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

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


I need to retrieve images corresponding to post with id = 1. The following is my implementation to retrieve images:

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


But, the problem is I am not able to get all images in
imgArray
to be able to send to
completion handler
. Below is the output of calling
retrieveImagesForPost
with post id ==1.

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


The images are retrieved after the
completion handler
is called. I tried the
dispatch groups
and the
semaphores
approach as described in the following post. But the results are still the same. How can I make
completion handler
to wait for all images to be fetched from Firebase?

Answer

Keep a counter that you increase as each image is loaded. Once the counter reaches the length of the snapshot.children list, you're done and call your completion handler.

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

You should probably add some error handling in the above, but in general this approach is tried and tested.

Comments