How to fix the asynchronous nature of my appending function?

280 views Asked by At

I have a query set up to pull data from a database (Parse-server hosted by heroku) and append it to an array; within this query is another query that is used to pull info from a different class but also used to append another array. I think because I use .findObjectsinBackground it happens asynchronously, which leads to an issue. Here is the code (generalized):

    func getQueries(completion: (() -> Void)?){

        let searchQuery = PFQuery(className: "Etc")         
        searchQuery.findObjectsInBackground(block: { (objects, error) in

            if let objectss = objects{

                for object in objectss {
                    //append some arrays
                    let otherQuery = PFQuery(className: "OtherClass")
                    otherQuery.whereKey("user", equalTo: object["User"] as String)
                    otherQuery.findObjectsInBackground(block: {(objects, error) in
                        if let objectss = objects{
                            for object in objectss{
                                array.append(object["ProfPic"] as PFFile)
                                print("\(array) and its count is \(array.count)") //this returns a non 0 value
                            }
                        }
                        completion!()
                    })

            print("\(array) and its count is \(array.count)") //this returns 0
                }
            }
         })
    }

array's count is returned as non 0 once it has been appended in its own closure, but returned as 0 outside of its closure. This is a problem since the arrays are used in iterating through to display information. Is there anyway to make sure before the overall closure of searchQuery is done, the otherQuery's append is already complete? (Also, the fact that it is happening asynchronously causing the problem is a guess... I could be wrong)

1

There are 1 answers

2
shallowThought On BEST ANSWER

In the later case, you are printing the count bofore the data is fetched, e.g. outside the completion block of findObjectsInBackground.

You can wrap the whole thing in an own method with completion block:

func fetchData(_ completion: () -> Void) {

    searchQuery.findObjectsInBackground(block: { (objects, error) in
        guard let objectss = objects else {
            completion() 
        }

        for object in objectss {
            let otherQuery = PFQuery(className: "OtherClass")
            otherQuery.whereKey("user", equalTo: object["User"] as String)
            otherQuery.findObjectsInBackground(block: {(objects, error) in

                guard let objectss = objects else {
                    completion()
                }

                for object in objectss{
                    array.append(object["ProfPic"] as PFFile)
                }

                print("In loop: \(array) and its count is \(array.count)")                
                completion()
            })
        }
    })
}

And than all it like this:

fetchData() {
     print("After completing: \(array) and its count is \(array.count)")
    // do stuff with your fetched data and display it
    // "use in iterating through to display information" here
}

Update:

In your updated question you are callin completion!() in success case only. You have to call it in any case:

...
if let objectss = objects 
    ...
    completion!()
} else {
    completion!()
} 
...