Извлечение данных из Firebase путем объединения таблиц в 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
}
}


Мне нужно получить изображения, соответствующие post с 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. Ниже приведен вывод вызова retrieveImagesForPost с post id ==1.

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


Изображения извлекаются после вызова completion handler. Я попробовал dispatch groups и подход semaphores, описанный в следующем посте . Но результаты все те же. Как я могу заставить completion handler ждать, пока все изображения будут извлечены из Firebase?

601   2  

2 ответов:

Держите счетчик, который вы увеличиваете по мере загрузки каждого изображения. Как только счетчик достигнет длины списка 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)
            }
        })
    }
})

Вероятно, вам следует добавить некоторую обработку ошибок в вышеизложенном, но в целом этот подход опробован и проверен.

Другой ответ на эту проблему-использовать 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)
})

Comments

    Ничего не найдено.