0

I cannot get a [UIImage?] return from this function. The getDataInBackgroundWithBlock won't let me set a return value other than Void in. However, that block does add to the iconArray as it iterates through. But once outside of the block the array is empty again. You will see in the code below the comments where the array does and does not print correctly.

The call does connect to the DB, all data is flowing. It's simply returning that array that is the hang up.

class callData {


func queryImages() -> [UIImage?] {

    var iconArray: [UIImage?] = []

    var query: PFQuery = PFQuery(className: "QuestionMaster")
    query.findObjectsInBackgroundWithBlock { (objects: [AnyObject]?, error: NSError?) -> Void in

        for object in objects! {

            let imageFiles = object["questionImage"] as! PFFile

            imageFiles.getDataInBackgroundWithBlock({
                (imageData: NSData?, error: NSError?) -> Void in
                if (error == nil) {

                    let image = [UIImage(data: imageData!)]
                    iconArray += image        //adds item to array correctly
                }

                println(iconArray) //prints correct array here

            }) //getDataInBackgroundWithBlock close

            println(iconArray) //does not print correct array here

        } //for-loop close

    }

    return iconArray //returns empty array

}

}
Max Phillips
  • 6,991
  • 9
  • 44
  • 71
  • duplicate: http://stackoverflow.com/questions/22267865/returning-method-object-from-inside-block – Wain Apr 19 '15 at 20:15
  • @Wain I disagree with that duplicate, this question has an asynchronous call inside a for loop inside another asynchronous call, this will behave different that the link you provided. – milo526 Apr 19 '15 at 20:32
  • @milo526, it's the same principle, though I'll agree that the inner loop adds an additional level of complexity. Arguably that inner loop should be extracted... – Wain Apr 19 '15 at 20:39

1 Answers1

2

As your function states the block is executed in the background (on a asynchronous thread. This means that it will load in the background but will also continue the rest of the function thus returning an empty array.

To fix this you should use a completion handler for your block in background.

func queryImages(onComplete:(images: [UIImage?])-> Void){
    var iconArray: [UIImage?] = []
    var query: PFQuery = PFQuery(className: "QuestionMaster")
    query.findObjectsInBackgroundWithBlock { (objects: [AnyObject]?, error: NSError?) -> Void in

    for object in objects! {

        let imageFiles = object["questionImage"] as! PFFile

        let imageData = imageFiles.getData()
        let image = UIImage(data:imageData!)
        iconArray.append(image)

        println(iconArray)
    }
    onComplete(images: iconArray)
    }
}

Although untested above code should work

The Asynchronous data retrieval inside your for loop has been replaced in favor of a synchronous call to ease the project

milo526
  • 5,012
  • 5
  • 41
  • 60
  • That question is irrelevant to me, whether it is possible or not, you shouldn’t do it ;) Dispatch_async should primarily be used for UI Changes inside a completion block – milo526 Apr 19 '15 at 20:20
  • @spacemonkey i’ll take back that answer, I think it can also be used inside a for loop inside an asynchronous call. Please see edited answer – milo526 Apr 19 '15 at 20:44