2016-07-10 3 views
3

Я пытаюсь извлечь данные из двух разных таблиц Firebase. Вот структура таблицы:Извлечь данные из Firebase путем объединения таблиц в iOS

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

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

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

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

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

ответ

4

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

каким образом ваша функция изменения я должен был бы присоединиться к 3 узлов (отношения) в Firebase – Learn2Code

+0

если (счетчик == snapshot.childrenCount) выдает ошибку !? – Learn2Code

1

Еще один ответ на эту проблему - использовать 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'. Ввод и выход из группы правильный. –

Смежные вопросы