I'm trying to move my app over to MVC, I have a Parse query which I've moved over to a function in my model class, the function returns a Bool.
When the button in my ViewController below is pressed the model function 'parseQuery' should be run, return a bool and then I need to use that bool to continue. At the moment, the if statement is executed before the function has completed so it always detects false.
How can I ensure that the if statement is completed once the function has completed?
@IBAction func showAllExpiredUsers(sender: AnyObject) {
var success = searchResults.parseQuery()
if success {
print("true")
} else {
print("false")
}
//I have also tried:
searchResults.parseQuery()
if searchResults.parseQuery() {
print("true")
} else {
print("false")
}
You have a few options, but the issue is due to asynchronous calls.
Does Parse expose the same function, with a completion block?
If yes, then you place the processing of the Bool inside the completion block, which is called when the async task is completed.
If not, which I doubt, you could create an NSOperationQueue, with a maxConcurrency of 1 (so it is serial) and dispatch the calls onto the queue with
func addOperationWithBlock(_ block: () -> Void)
This is called on the queue. You would need to store the success bool globally so that you can access it inside the second queued block operation, to check the success state.
Update:
I haven't used parse, but checking the documentation for findObjectsInBackgroundWithBlock (https://parse.com/docs/ios/guide#queries) it takes a completion block where you can process the result, update your bool.
I'm not sure what you are trying to do. You don't need to have the success state of the query. You can check
if (!error) {
// do stuff
} else {
//error occurred - print("error \(error.localizedDescription)"
}
Check the example.
What you need to understand is threading. The async task provides a completion block because its asynchronous, it gets dispatched onto another thread for processing. I'm not sure how much you know about threading but there is something called a thread pool. This thread pool is accessed by Queues. The thread pool is managed by the OS, and makes sure available threads can be used by queues that need work done. As users interact with an application, this (and all UI work) is done on the main thread.
So whenever some processing is going to interfere with possible interaction or UI updates, it should be dispatched (Grand Central Dispatch) or queued (NSOperationQueue, built on top of GCD) off of the main thread.
Anyway, this is why the findObjectsInBackgroundWithBlock
call is dispatched off the main thread, because otherwise it would block the main thread until its done, ruining the experience for the user. Also, if the main thread is blocked for more than 1 minute (last time I checked), the OS's watchdog will kill your process.
So yeah, assigning a boolean to the return of the block, would get the return of the function, which occurs before the completion block is done. The completion block is where you code some stuff to be done after the function completes. So the query gets dispatched onto another thread and starts processing, the thread that sent this work off for processing, continues with the rest of its execution. So checking the boolean directly after, wouldn't work because the other thread isn't complete. Even if the other thread finished in time, what is connecting the background thread with the main thread?
This is the beauty of blocks (function pointers), it's a lot cleaner and optimized and keeps code compact. The old way, which is still is use for some older frameworks, is delegates, which detaches the calling code with the callback and adds a delegate dependency. Blocks are beautiful.
Its also important to note that completion blocks don't always get called on the main thread. In many cases its up to you to dispatch the work back to the main thread, to handle any UI work that needs to be done with the objects available inside the completion block.