2017-01-05 2 views
0

У меня есть три асинхронных вызова. Один возвращает данные и два обратных изображения из S3 с использованием firebase. У меня есть один файл DispatchQueue и три группы отправки. Мне нужен способ для их выполнения синхронно, но они этого не делают! Я пробовал все, и .notify выполняется немедленно, что неправильно.Grand Central Dispatch Multiple DispatchGroups

Выход этого является:
изображения сделано
все сделано
group.notify делается
getImages() делается

То, что я хочу, чтобы понять, почему imagesdone выполняется до group.notify? Мне нужно выполнить первую группу, затем imageGroup, а затем avaGroup.

У меня есть три асинхронных вызова, а 2-й/3-й - несколько асинхронных вызовов. Как я могу дождаться их завершения, а затем выполнить последующие вызовы?

func loadFriendPhotos() { 

    let backgroundQueue = DispatchQueue(label: "com.app.queue", 
             qos: .utility, 
             target: nil) 

    let group = DispatchGroup() 
    let imageGroup = DispatchGroup() 
    let avaGroup = DispatchGroup() 
    typealias tempAlias = (username:String, imageURL: String, pathUrl:String) 

    var tempAliasArray = [tempAlias]() 
    var imageArray = [UIImage]() 
    var avaImageArray = [UIImage]() 

    group.enter() 
    let workItem = DispatchWorkItem { 
     databaseRef.child("friendPhotos").child(globalUsername).observeSingleEvent(of: .value, with: { (snapshot) in 
      if snapshot.exists() { 

       let enumerator = snapshot.children 
       var childrenCount = snapshot.childrenCount 


       while let rest = enumerator.nextObject() as? FIRDataSnapshot { 

        let name = rest.childSnapshot(forPath: "username").value as! String 
        let downloadURL = rest.childSnapshot(forPath: "downloadURL").value as! String 
        let uid = rest.childSnapshot(forPath: "uid").value as! String 
        let pathURL = rest.childSnapshot(forPath: "pathURL").value as! String 
        let downloadURLRef = storage.reference(forURL: downloadURL) 

        let newTempAlias = tempAlias(name, downloadURL, pathURL) 
        tempAliasArray.append(newTempAlias) 
       } 
       group.leave() 
      } 
     }) 
    } 

    func getAvaImages() { 
     for index in tempAliasArray{ 
      avaGroup.enter() 
      let avaItem = DispatchWorkItem { 
       let avaURLRef = storage.reference(forURL: index.1) 
       avaURLRef.data(withMaxSize: 2 * 1024 * 1024) { (data,error) in 
        if (error == nil) { 
         print("success!") 
         let picData = UIImage(data:data!) 
         avaImageArray.append(picData!) 

        } else { 
         print(error?.localizedDescription) 
        } 
        print("we left getAvaImages()") 
        avaGroup.leave() 

       } 
      } 
      backgroundQueue.async(execute: avaItem) 
     } 
    } 

    func getImages() { 
     for index in tempAliasArray{ 
      imageGroup.enter() 
      let imageItem = DispatchWorkItem { 
       let downloadURLRef = storage.reference(forURL: index.1) 
       downloadURLRef.data(withMaxSize: 2 * 1024 * 1024) { (data,error) in 
        if (error == nil) { 
         let picData = UIImage(data:data!) 
         imageArray.append(picData!) 
        } else { 
         print(error?.localizedDescription) 
        } 
        print("we left getImages()") 
        imageGroup.leave() 
       } 
      } 
      backgroundQueue.async(execute: imageItem) 
     } 
    } 

    backgroundQueue.sync(execute: workItem) 

    group.notify(queue: DispatchQueue.main, execute: { 
     print("group.notify is done") 
     getImages() 
    }) 
    imageGroup.notify(queue: DispatchQueue.main, execute: { 
     print("images done") 
     getAvaImages() 
    }) 
    avaGroup.notify(queue: DispatchQueue.main, execute: { 
     print("all is done") 
    }) 
} 

ответ

0

Вы звоните imageGroup.notify в точке, что нет ничего в imageGroup, поэтому он немедленно уведомляет. Аналогично, avaGroup уведомляет об этом сразу же, так как он пуст в том месте, которое вы его называете.

Но я не понимаю всю косвенность и группы и три массива. Почему вы должны дождаться загрузки всех изображений до того, как будете иметь дело с каждым изображением? Почему бы просто не начать следующий шаг в исходном цикле только для одного элемента? Что-то вроде этого:

var allTheResults = [] 

group.enter() // Enter once for the top-level 
kickOffAsyncWithCompletion { resultList in 

    for item in resultList { 
     let resultThing = doSomeStuffToSetupNextLevel() 

     group.enter() // Enter once per thing we iterate over 

     kickOffNestedAsync(with: resultThing, completion: { result in 
      let finalResult = computeFinalResult(fromResult: result) 
      allTheResults.append(finalResult) 
      group.leave() // leave once per thing we iterate over 
     }) 
    } 
    group.leave() // leave once for the top level 
} 

group.notify { doThing(withFinalResults: allTheResults) } 

Если вы хотите, чтобы скоординировать конечную точку множества операций, вы хотите, чтобы все эти операции будут работать с одной и той же группы, а не отдельных групп на одну операцию.

+0

hi @ rob-napir, являются ли вызовы group.enter() одной и той же диспетчерской группой? – MattEm

+0

Более широкий вопрос, если вы делаете несколько асинхронных вызовов, используете ли вы одну и ту же группу, или если бы был kickoffAsyncWithCompletion2 на том же уровне, что и kickOffAsyncWithCompletion, это была бы другая группа. – MattEm

+0

. Пробник Im Imception - это группа1 автоматически выходит, вызывая group1.notify, который не должен произойти. Это не происходит и запускается после того, как NOT Nesting group.enter() – MattEm