5

I'm going to try to explain this as best as I can.

I am using Parse.com and returning data from a Parse database class. I want to put this parse.com call in its own function in a custom class. The problem I am having is the completion. Where does it go? I've tried many different versions of adding it to my function but it isn't working.

Here is the function that takes the class name, table name, and sort descriptor and returns an array:

func queryDataInBackgroundWithBlock(parseClass:String, parseObject:String, sortDescriptor:NSSortDescriptor) -> [Any]

When I add the completion to it I use (which may not be correct):

func queryDataInBackgroundWithBlock(parseClass:String, parseObject:String, sortDescriptor:NSSortDescriptor, completion: (result: Any)->Void)

Now inside the function I use the Parse.com code to go out and get the data

    query.findObjectsInBackgroundWithBlock {
        (objects: [AnyObject]!, error: NSError!) -> Void in
        if error == nil {

            // Do something with the found objects
            for object in objects {
                self.arrayOfObjects.append(object[parseObject]!)
            }

        } else {
            // Log details of the failure
            println("Error: \(error) \(error.userInfo!)")
        }

    }

My goal here is to send parameters to my class function, get the data from parse.com and then return the data as an Array AFTER the async call

I am trying to call it like this:

myClass.queryDataInBackgroundWithBlock("databaseName", parseObject: "columnName", sortDescriptor: orderBy){
    (result: Any) in
    println(result)
}

It's almost like it is a nested completion. How do I return the array after it is completed? Is it handed off to the function which then returns it, or does it need to return in the nested code, or what? It retrieves the data but the problem is the return AFTER completion.

UPDATE: As I stated in the comment below:

query.findObjectsInBackgroundWithBlock({
    (objects: [AnyObject]!, error: NSError!) -> Void in
    if error == nil {

        // Do something with the found objects
        for object in objects {
            self.arrayOfObjects.append(object[parseObject]!)
        }

    } else {
        // Log details of the failure
        println("Error: \(error) \(error.userInfo!)")
    }

}, completion: {
     //do something here
})

This is returning the error: "Extra argument completion in call" I'm not sure how to add the completion at the end of the block so I added () around the block and inserted the completion. This is obviously wrong but I'm not sure how to add the completion at the end of the block as matt has suggested

UPDATE 2:

    func queryDataInBackgroundWithBlock(parseClass:String, parseObject:String, sortDescriptor:NSSortDescriptor) -> [Any]{
        var query = PFQuery(className:parseClass)

        if sortDescriptor.key != "" {
            query.orderBySortDescriptor(sortDescriptor)
        }

        query.findObjectsInBackgroundWithBlock {
            (objects: [AnyObject]!, error: NSError!) -> Void in
            if error == nil {

                // Do something with the found objects
                for object in objects {
                    self.arrayOfObjects.append(object[parseObject]!!)
                }

            } else {
                // Log details of the failure
                println("Error: \(error) \(error.userInfo!)")
            }

        }

        return self.arrayOfObjects  //<-- needs to move to completion
    }
AppDever
  • 687
  • 1
  • 7
  • 17
  • Please copy and paste, in full, into the question, your _entire_ implementation of `func queryDataInBackgroundWithBlock(parseClass:String, parseObject:String, sortDescriptor:NSSortDescriptor, completion: (result: Any)->Void)`. – matt Dec 16 '14 at 21:13
  • updated answer - you will see that I am simply doing what I have consistently been saying you should do... – matt Dec 16 '14 at 22:48

1 Answers1

6

Inside the function queryDataInBackgroundWithBlock you receive the completion block under the name completion. It takes one parameter. So the last thing you do, after you have the data, is call it, handing it the data:

completion(result:myData)

And since query.findObjectsInBackgroundWithBlock is itself async, you will need to make that call as the last thing inside the block of query.findObjectsInBackgroundWithBlock.

Like this:

func queryDataInBackgroundWithBlock(
    parseClass:String, parseObject:String, sortDescriptor:NSSortDescriptor, 
    completion: (result: Any)->Void) 
{
    var query = PFQuery(className:parseClass)

    if sortDescriptor.key != "" {
        query.orderBySortDescriptor(sortDescriptor)
    }

    query.findObjectsInBackgroundWithBlock {
        (objects: [AnyObject]!, error: NSError!) -> Void in
        if error == nil {

            // Do something with the found objects
            for object in objects {
                self.arrayOfObjects.append(object[parseObject]!!)
            }

        } else {
            // Log details of the failure
            println("Error: \(error) \(error.userInfo!)")
        }
        completion(result:self.arrayOfObjects)
    }

}
matt
  • 515,959
  • 87
  • 875
  • 1,141
  • I actually don't need to pass a parameter to the completion so should it say completion:()->[Any]. And that findIbjectsInBackground is a parse.com function. I think you're telling me to put the completion in there but I'm not sure how to do that – AppDever Dec 16 '14 at 14:55
  • Yes you do have to pass a parameter (actually it's an argument). You yourself have declared `completion` as having the type `(result: Any)->Void`. You _must_ supply a `result` argument when you call `completion(...)`. – matt Dec 16 '14 at 14:59
  • Look at the code you cited above. _You_ are calling `query.findObjectsInBackgroundWithBlock` _with a block_. That block is _your_ code. I'm saying put the call to `completion(...)` in there, at the end, to signify that the block is done. – matt Dec 16 '14 at 15:01
  • I've tried 20 different ways to do this and get an error every time. What seems like it SHOULD work is query.findObjectsInBackgroundWithBlock({ BLOCK CODE }, completion: { ... }) but I get the error **Extra argument completion in call** which is telling me that I'm sending a completion argument to findObjectsInBackgroundWithBlack which is part of the PFQuery class written by parse.com. If I try without the () then the error is **Consecutive statements on a line must be separated by ;** – AppDever Dec 16 '14 at 19:37
  • Well, that would be another question. You're making some kind of basic Swift syntax error. But that has nothing to do with the question you asked. You asked how to do this and, based on the info you provided, I tried to help you. I don't know what your error-generating code looks like so how can I help you with it? If you are getting syntax errors, then try to implement what I said to implement and ask a _new_ question (or even edit the current question) showing your _actual code_ and the _actual error_ you're getting. I can't help you correct your code unless I can see the code to correct. – matt Dec 16 '14 at 19:45
  • I'm getting syntax errors trying to "implement what you said to implement." It's not a different question. I'm obviously not implementing it properly – AppDever Dec 16 '14 at 20:00
  • Sure, but you still haven't shown me what you are actually doing. Are you trying to _stop_ me from helping you? If so, you are succeeding beautifully! I'm not going to _guess_ what your code looks like. You already know so why not _show_ it? – matt Dec 16 '14 at 20:17
  • Ok, I added the code to the original question that is the **same as the code** in the comment 4 comments above this – AppDever Dec 16 '14 at 21:05
  • Good but you did not do what I said. You are already receiving `completion:` as a parameter of your `func queryDataInBackgroundWithBlock(parseClass:String, parseObject:String, sortDescriptor:NSSortDescriptor, completion: (result: Any)->Void)`. Now you are inside that method, so you already _have_ `completion`. So now just call it: `completion(data)`. Don't add the extra curly braces, colon, etc. Just call it! – matt Dec 16 '14 at 21:07
  • I get it now. When you said put it in the query call I thought you meant to remove it from the function. Thanks for your help – AppDever Dec 16 '14 at 23:20
  • Thanks @matt that was very helpful for me too! – Icaro Jul 26 '15 at 00:42
  • Glad I could help, @Icaro ! – matt Jul 26 '15 at 01:19