So I have a PFFile object from Parse, and I'm trying to create a function that retrieves the UIImage representation of that PFFile and returns it. Something like:
func imageFromFile(file: PFFile) -> UIImage? {
var image: UIImage?
file.getDataInBackgroundWithBlock() { (data: NSData?, error: NSError?) -> Void in
if error != nil {
image = UIImage(data: data!)
}
}
return image
}
However, the problem here is obvious. I'm going to get nil every time because the getDataInBackroundWithBlock function is asynchronous. Is there any way to wait until the UIImage has been retrieved before the image variable is returned? I don't know if using the synchronous getData() is an efficient way to go in this case.
What you want is exactly what the promise/future design pattern does. There are many implementations in Swift. I will use as an example the excellent BrightFutures library. (https://github.com/Thomvis/BrightFutures)
Here the code:
Explanation: what you basically do is creating a "promise" that there will be a result in the "future". And you are returning this future-promise immediately, before the async method completes.
The caller of this method will handle it like this:
In the onSuccess handler you are doing all the stuff with the successfully downloaded image. If there is an error you handle it in the onFailure handler.
This solves the problem of returning "nil" and is also one of the best practices to handle asynchronous processes.
I do not recommend this
I have written a small library for Swift 2.0 which can convert between synchronous and asynchronous methods, which would be what you're asking for. It can be found here. Be sure to read the disclaimer which explains in which scenarios it's okay to use it (most likely not in your case)
You'd be able to use it like this:
Yes, it is possible to do this. Its called a
closure
, or more commonly acallback
. Acallback
is essentially a function that you can use as an argument in another functions. The syntax of the argument isReturnType
is usuallyVoid
. In your case, you could useThe syntax of calling a function with one callback in it is
And the syntax of calling a function with several callbacks is (indented to make it easier to read)
If the function escapes the function (is called after the function returns), you must add @escaping in front of the argument type
You're going to want to use a single callback that will be called after the function returns and that contains
UIImage?
as the result.So, your code could look something like this
And to call it, you could simply use