Получать данные из 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
         }
 }

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

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

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

Ответы на вопрос(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)
            }
        })
    }
})

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

 Learn2Code17 июн. 2017 г., 01:49
как меняется ваша функция мне нужно было бы объединить 3 узла (отношения) в Firebase
 Learn2Code18 июн. 2017 г., 21:27
if (counter == snapshot.childrenCount) выдает ошибку !?

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)
})
 Ernesto Fernandez10 авг. 2017 г., 23:24
Это намного лучше, чем использование счетчика, как в принятом ответе. Хотя, чтобы он работал правильно,dispatchGroup должен быть создан внутри первого блока наблюдения и уведомлен послеfor, Вход и выход из группы - это правильно.

Ваш ответ на вопрос