2017-01-05 7 views
0

私は3つの非同期呼び出しを持っています。 1つはデータを返し、もう1つはfirebaseを使ってS3からの2つの戻り画像です。 DispatchQueueというバックグラウンドとディスパッチグループが3つあります。私は彼らが同期して実行する方法が必要ですが、そうではありません!私はすべてを試しましたが、すぐに実行されます。間違っています。Grand Central Dispatch Multiple DispatchGroups

はこのの出力はです:
すべてを行って
画像が
group.notify)は(
getImagesをやっている私は理解して欲しい

に行われて行われるimagesdoneである理由でありますgroup.notifyが実行される前に実行されますか?私は最初のグループ、次にimagesGroup、そしてavaGroupを実行する必要があります。

私は本質的に3つの非同期呼び出しを持ち、第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ではありませんので、それはすぐに通知した時点でimageGroup.notifyを呼んでいます。同様に、avaGroupは、呼び出した時点で空であるためすぐに通知します。

しかし、すべてのインダイレクションとグループと3つの配列はわかりません。各画像を処理する前に、すべての画像がダウンロードされるのを待たなければならないのはなぜですか?なぜただ1つの要素について元のループ内の次のステップを開始するのはなぜですか?このような何か:

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は、同じdispatchGroupに対するgroup.enter()呼び出しの両方ですか? – MattEm

+0

複数の非同期呼び出しを行っている場合、同じグループを使用するか、kickOffAsyncWithCompletionと同じレベルのkickoffAsyncWithCompletion2がある場合は、別のグループになる可能性があります – MattEm

+0

問題が発生している場合、group1は自動的に終了し、group1.notify、それは起こるべきではありません。これは起こりません。そして、グループが入れ子になっていないときにトリガーします。group()の – MattEm

関連する問題