Search code examples
swiftmultithreadingparse-platformbackground-processcompletionhandler

Threading CompletionHandler Swift


i try to get data from parse server. Therefore it takes 2 backgroundthreads. But i dont get it managed to wait for the completion in a right way. So i have splitted it up like following code:

 func load(loadCompletion: @escaping () -> ()) {
    let delegate = object as! AppDelegate
    parseQuery.findObjectsInBackground { (result: [PFObject]?, error: Error?) in
        self.getAllData(result: result, delegate: delegate, error: error) {
            loadCompletion()
        }
    }
}

func getAllData(result: [PFObject]?, delegate: AppDelegate, error: Error?, allDataCompletion: @escaping () -> ()) {
    if error == nil && result != nil {
        for obj in result! {
            let date: Date = obj["Date"] as! Date
            let coordinates: PFGeoPoint = obj["Coordinates"] as! PFGeoPoint
            let imageFile: PFFileObject = obj["Image"] as! PFFileObject
            let lat: CLLocationDegrees = coordinates.latitude
            let long: CLLocationDegrees = coordinates.longitude
            let cllCoordinates = CLLocationCoordinate2D(latitude: lat, longitude: long)
            self.getImageData(imageFile: imageFile) { (image) in
                let poo = Poo(coordinates: cllCoordinates, dateTime: date, image: image)
                delegate.poos.append(poo)
            }
        }
        allDataCompletion()
    }
}

func getImageData(imageFile: PFFileObject, imageDataCompletion: @escaping (UIImage?) -> () ) {
    var image: UIImage? = nil
    imageFile.getDataInBackground { (data, error) in
        if error == nil && data != nil {
            image = UIImage(data: data!)
        }
        imageDataCompletion(image)
    }
}

So, i want so set up the array in the delegate, but unfortunately the loadCompletion() gets called before the array is filled. Please help me to get this running in right order. Thanks!


Solution

  • A simple solution is to modify your getAllData function and call allDataCompletion after getting image data for the last object.

    func getAllData(result: [PFObject]?, delegate: AppDelegate, error: Error?, allDataCompletion: @escaping () -> ()) {
        if error == nil && result != nil {
            for (idx, obj) in result!.enumerated() {
                let date: Date = obj["Date"] as! Date
                let coordinates: PFGeoPoint = obj["Coordinates"] as! PFGeoPoint
                let imageFile: PFFileObject = obj["Image"] as! PFFileObject
                let lat: CLLocationDegrees = coordinates.latitude
                let long: CLLocationDegrees = coordinates.longitude
                let cllCoordinates = CLLocationCoordinate2D(latitude: lat, longitude: long)
                self.getImageData(imageFile: imageFile) { (image) in
                    let poo = Poo(coordinates: cllCoordinates, dateTime: date, image: image)
                    delegate.poos.append(poo)
                    if idx == result!.endIndex-1{
                        allDataCompletion()
                    }
                }
            }
    
        }
    }
    

    or Use DispatchGroup / Synchronizing Async Code