9

I am relatively new to Swift and Xcode in general and am finding a lot of difficulty trying to figure this out.

I am developing an app that utilizes the Parse.com backend server. In order not to block the main thread, whenever the app downloads anything from the server, it is done on a different thread, asynchronously. However the rest of the code continues to execute on the main thread, and it crashes when the data it is supposed to have from the server has not downloaded yet. I would like to know how to call functions to run after the asynchronous function finishes, and this has to be done for functions in separate files.

I read that closures might help with this, but I found there syntax very difficult and an explanation would be greatly appreciated. But any way would be very helpful.

Thanks

Acoop
  • 2,586
  • 2
  • 23
  • 39

2 Answers2

14

Well, you simply call the function at the end of the asynchronous callback. That is when the asynchronous callback has ended - it is when everything else in the asynchronous callback has finished! So, for example:

func myMethod() {
    // ... code ...
    somebody.doSomethingWith(someObject, asynchronousCallback: {
        (thing, otherThing) in
        // ... do whatever
        // --> CALL THE FUNCTION!
    })
    // ... code ...
}

If the problem is that you do not know what function to call, you can configure your surrounding function / object so that someone can hand you a function which is then what you call in the spot where I said "call the function" in the above.

For example:

func myMethod(f:() -> ()) { // we receive the function as parameter
    // ... code ...
    somebody.doSomethingWith(someObject, asynchronousCallback: {
        (thing, otherThing) in
        // ... do whatever
        // --> CALL THE FUNCTION, by saying:
        f()
    })
    // ... code ...
}
matt
  • 515,959
  • 87
  • 875
  • 1,141
  • Can you explain how to hand over a function? I understood beforehand that you run the function where you wrote "call the function, " but the function, like I said, is in a different file. The specific case that I am working with right now is that I wrote a function that first checks if the object being looked for is in the local data store, and if not, it checks the server. Since I want this to run everywhere, I put it in a separate file. But I still need it to call functions in the class that called it. Thanks again. – Acoop May 08 '15 at 22:28
  • I can certainly explain it _linguistically_. In Swift, functions are first-class citizens, so function A can hand function B to function C, which can store function B. Then, function C or some other function with access to the stored function B can _call_ function B. That is how all callbacks work. When you say `UIView.animateWithDuration() { ... }`, that is what you are handing over to Cocoa - a function which it will call in order to perform the animation. See also my book: http://www.apeth.com/swiftBook/ch02.html#_function_as_value – matt May 08 '15 at 23:07
  • However, how you choose to do it _architecturally_ is up to you. In the example above, `myMethod` might take a function as parameter; then at "call the function", you call it. But there are lots of other possible scenarios. See this sample code for an example: https://github.com/mattneub/Programming-iOS-Book-Examples/blob/master/bk2ch24p842downloader/ch37p1099downloader/MyDownloader.swift – matt May 08 '15 at 23:10
  • And I've revised my answer to illustrate the idea of receiving a function so you can call it later. – matt May 08 '15 at 23:16
3

Expanding on Matt's answer, you can make myMethod a method that takes a closure as a parameter:

​func​ ​myMethod​(​completionBlock​: (result: String) -> ()) 
{
    // ... code ...
    somebody.doSomethingWith(someObject, asynchronousCallback: {
        (thing, otherThing) in
        // ... do whatever
        completionBlock(thing)
    })
    // ... code ...
}
Duncan C
  • 128,072
  • 22
  • 173
  • 272