2

I am using DispatchGroup to download data from 3 different APIs, once this is done I want to return the new created consolidated object from my function. Now Although DispatchGroup is working fine and I am getting data but I am not able to return it to calling function. Following is my function:

func getHowToInfo(materialNo: String) -> Observable<HowToInfo> {
    return Observable.create{ observer in
        let dispatchGroup = DispatchGroup()

        _ = self.getMaterialInfo(materialNo: materialNo).subscribe(onNext:{ material in

            let howto = HowToInfo(videos: [], documents: [], applications: [])

            if (material.documentTargetId?.count)! > 0 {
                dispatchGroup.enter()
                _ = self.materialRepo?.API1(targetIDs: material.documentTargetId!).subscribe(onNext:{documents in
                    howto.documents = documents
                    dispatchGroup.leave()
                }, onError: { (error) in
                    dispatchGroup.leave()
                })
            }
            if (material.applicationDescription?.count)! > 0 {
                dispatchGroup.enter()
                _ = self.materialRepo?.API2(materialNo: materialNo).subscribe(onNext:{applications in
                    howto.applications = applications
                    dispatchGroup.leave()
                }, onError: { (error) in
                    dispatchGroup.leave()
                })
            }
            if ((material.videoApplicationTargetId?.count) != nil && (material.videoApplicationTargetId?.count)! > 0) {
                dispatchGroup.enter()
                _ = self.materialRepo?.API3(targetIDs: material.videoApplicationTargetId!).subscribe(onNext:{videos in
                    howto.videos = videos
                    dispatchGroup.leave()
                }, onError: { (error) in
                    dispatchGroup.leave()
                })
            }else if ((material.videoSupportTargetId?.count) != nil && (material.videoSupportTargetId?.count)! > 0) {
                dispatchGroup.enter()
                _ = self.materialRepo?.API4(targetIDs: material.videoSupportTargetId!).subscribe(onNext:{videos in
                    howto.videos = videos
                    dispatchGroup.leave()
                }, onError: { (error) in
                    dispatchGroup.leave()
                })
            }

            dispatchGroup.notify(queue: .main, execute: {
                print("All functions complete ")
                observer.onNext(howto)
                observer.onCompleted()
            })
        })
        return Disposables.create()
    }
}

calling function:

func loadHowToUseList(materialNo: String){
    self.serviceMaterial.getHowToInfo(materialNo: materialNo).subscribe({
        howToUse in
        print(howToUse)
    }).disposed(by: DisposeBag())
}

I am not able to get my object in subscribe method above, it never runs.

Panks
  • 565
  • 1
  • 7
  • 20

2 Answers2

1

Try adding

dispatchGroup.wait()

After your lines

        dispatchGroup.notify(queue: .main, execute: {
            print("All functions complete ")
            observer.onNext(howto)
            observer.onCompleted()
        })

And also, why don't just use Rx operators itself?

Every one of this could be an observer.onNext, then you try to observe on three events of this observable, and there is no need for onCompleted

user9335240
  • 1,739
  • 1
  • 7
  • 14
  • Actually all these calls are random, I don't know which one will complete first, I want to return the object once all 3 calls are completed – Panks May 06 '18 at 12:12
  • I also added dispatchGroup.wait() after but now notify block is not being called. – Panks May 06 '18 at 12:17
1

I think you can achieve desired behaviour using combineLatest and skipWhile operators. Roughly implementation would be like this:

    let api1 = Observable.of(["documents"])    //Replace with observable to download docs
    let api2 = Observable.of(["applications"]) //Replace with observable to download apps
    let api3 = Observable.of(["videos"])       //Replace with observable to download videos

    Observable.combineLatest(api1, api2, api3){(docs, apps, videos) in
        return (docs, apps, videos)
    }.skipWhile{ (docs, apps, videos) in
        return docs.count == 0 && apps.count == 0 && videos.count == 0
    }.subscribe(onNext:{(docs, apps, videos) in

    })
    .disposed(by:disposeBag)
Farooq Zaman
  • 495
  • 1
  • 6
  • 21