Runeaway3
Runeaway3

Reputation: 1449

How to ensure a query happens before another query within the same function?

I have a function which has multiple queries set up in it. The function is long and involves alot, but works perfectly, save for one issue. There is a query which depends on some information with the query before and it occasionally crashes the app when the query before it is not totally done and caused the second one to unwrap a nil value. Here is the general setup:

func QueryandAppend(completion: (() -> Void)?){
    let userLinkQuery = PFUser.query()//query1
    userLinkQuery?.findObjectsInBackground(block: { (objects, error) in
        if let users = objects{
            for object in users{
                if let user = object as? PFUser{
                    userLinkArray[user.objectId!] = user.username
                }
            }
        }
        })

        let appendingQuery = PFQuery(classname: "Stuff")//query2
            appendingQuery.findObjectsInBackground { (objects, error) in
            for object in objects{
               creatorArray.append(userLinkArray[object["User"] as! String]!)
            }
            ...
            completion!()

    }

The completion handler is used to make sure the entire function (and all of the queries) have been completed before running something in the viewDidLoad(). How do I ensure, though, that within the function query1 is done before query2 can run?

Upvotes: 1

Views: 118

Answers (1)

David Berry
David Berry

Reputation: 41236

The prototypical way to do this with network and other asynchronous operations is to chain the operations, perhaps even break the individual network operations up each into a specific routine. The individual operations have completion callbacks, so just invoke your second routine from the completion of the first.

func QueryandAppend(completion: ((Bool) -> Void)?) {
    PFUser.query().findObjectsInBackground { (objects, error) in
        guard error == nil, let users = objects else {
            completion?(false)
            return
        }

        for object in users {
            if let user = object as? PFUser,
                let objectId = user.objectId {
                userLinkArray[objectId] = user.username
            }
        }

        PFQuery(classname: "Stuff").findObjectsInBackground { (objects, error) in
            if error != nil {
                // Handle error case
                completion?(false)
                return
            }

            for object in objects {
                creatorArray.append(userLinkArray[object["User"] as! String]!)
            }

            completion?(true)
        }
    }
}

Alternatively, for a more modern stylistic approach, you could take a look at a good Promise framework, such as PromiseKit

Upvotes: 2

Related Questions