1

I am trying to query my _User class for a specific objectId, and download an image from it.

The objectId passed through the userList is the correct one, if checked against the parse.com user table.

The array returned is always empty

Any help would be appreciated.

func imageArrayFromUserList(userList: [PFUser]) -> [UIImage] {
    var arrayToReturn: [UIImage] = []
    for user in userList {
        let objectID = user.objectId

        let query = PFUser.query()
        //let query = PFQuery(className: "_User")
        query!.whereKey("objectId", equalTo: objectID!)
        //query?.limit = 1
        query!.findObjectsInBackgroundWithBlock({ (results: [AnyObject]?, error: NSError?) -> Void in

            if error != nil{// This never prints anything to console
                println(error)
            }

            if let results = results as? [PFObject] {
                for object in results {
                    let userPicture = object["image"] as! PFFile

                    userPicture.getDataInBackgroundWithBlock {
                        (imageData: NSData?, error: NSError?) -> Void in
                        if error == nil {
                            if let imageData = imageData {
                                let image = UIImage(data:imageData)
                                arrayToReturn.append(image!)
                            }
                        }
                    }
                }
            }
        })
    }
    return arrayToReturn
}//end of imageArrayFromUserList method
14
  • That implies userList is empty so the for loop is never entered. Did you scope outwards with your breakpoints to find out what is getting executed? Put breakpoints to ensure the function is even being entered, and then at the top of the for loop, then at the top of the completion handler. Commented Aug 3, 2015 at 0:02
  • Also, see that error parameter? - don't ignore it. Check if it isn't nil and if it isn't then print it to see what went wrong. Commented Aug 3, 2015 at 0:06
  • @BaseZen userList is not empty, I put at breakpoint after "let objectID = user.objectId" and the value matches the one on parse.com. Commented Aug 3, 2015 at 0:29
  • @Paulw11 I tried printing an error, nothing happens because "query!.findObjectsInBackgroundWithBlock" does not seem to execute, it jumps it and goes to return line. I have breakpoints everywhere inside findobjects Commented Aug 3, 2015 at 0:31
  • That means the findObjectsInBackgroundWithBlock is definitely called, so your statement is incorrect. Step through every line of a single interation of the for loop and explain what happens. Are you saying the completion handler is never called? Was a breakpoint ever reached at the top of that? Commented Aug 3, 2015 at 0:32

1 Answer 1

1

You don't yet understand how completion handlers work. findObjectsInBackgroundWithBlock is designed to return immediately. It queues the finding task on a background thread. When the task completes, the completion handler code is called, probably on the same background thread.

See: How to explain callbacks in plain english? How are they different from calling one function from another function?

So you are debugging incorrectly, by expecting the debugger to hit breakpoints in the completion handler while stepping through the main thread that creates the background task. It doesn't work that way.

Since you're confused about debugging, helpful println()s at every stage, e.g.:

        if error != nil{// This never prints anything to console
            println(error)
        }
        else {
            println("No error!")
        }

        if let results = results as? [PFObject] {
            println("Got \(results.count\) results!")
            for object in results {
                println("Got result: \(object)!")
                let userPicture = object["image"] as! PFFile

                userPicture.getDataInBackgroundWithBlock {
                    (imageData: NSData?, error: NSError?) -> Void in
                    if error == nil {
                        println("Got user picture!")
                        if let imageData = imageData {
                            let image = UIImage(data:imageData)
                            arrayToReturn.append(image!)
                        }
                    }
                    else {
                        println("could not get user picture!")
                    }
                }
            }
        }
        else {
            println("What the hell? Results was not a [PFObject]")
        }

NOW with regard to just designing with callbacks correctly:

Your main function creates a request for the data, then immediately returns. It should be returning Void, not the array.

What is supposed to reflect the new data? Let's say it's a UITableView called myTableView. Then when the array has been filled in, you save it in a stored property of your class, and call myTableView.reloadData() in a dispatch_async call to the main thread. Where the UITableViewDataSource functions use the aforementioned stored array property.

I'm sure this is confusing. You need to read a whole tutorial on integrating data that arrives in the background.

Interestingly, I just did that for another user!

Tutorial in retrieving, mutating and saving array from Parse.com in Swift with UITableView

Sign up to request clarification or add additional context in comments.

3 Comments

I ended up using github.com/rs/SDWebImage to get the pictures loaded instead, i was not able to do it the other way. Problem fixed
But concepts not fully learned. :-( I see you accepted the answer. Was it helpful even though you didn't use it? (Is a teacher -->)
I accepted because you spent time trying to help me figure out the problem, it was helpful to clear up the confusion of running something in the background and not being able to breakpoint inside, and then realizing that the pictures won't load either and that I needed to load them asynchronously. Eventually I used sdwebimage to take care of loading the image async.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.