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.
Yes, it is possible to do this. Its called a closure
, or more commonly a callback
. A callback
is essentially a function that you can use as an argument in another functions. The syntax of the argument is
functionName: (arg0, arg1, arg2, ...) -> ReturnType
ReturnType
is usually Void
. In your case, you could use
result: (image: UIImage?) -> Void
The syntax of calling a function with one callback in it is
function(arg0, arg1, arg2, ...){(callbackArguments) -> CallbackReturnType in
//code
}
And the syntax of calling a function with several callbacks is (indented to make it easier to read)
function(
arg0,
arg1,
arg2,
{(cb1Args) -> CB1Return in /*code*/},
{(cb2Args) -> CB2Return in /*code*/},
{(cb3Args) -> CB3Return in /*code*/}
)
If your callback function escapes the main function (the callback is called after the main function returns), you must add @escaping in front of the callback's 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
func imageFromFile(file: PFFile, result: @escaping (image: UIImage?) -> Void){
var image: UIImage?
file.getDataInBackgroundWithBlock() { (data: NSData?, error: NSError?) -> Void in
//this should be 'error == nil' instead of 'error != nil'. We want
//to make sure that there is no error (error == nil) before creating
//the image
if error == nil {
image = UIImage(data: data!)
result(image: image)
}
else{
//callback nil so the app does not pause infinitely if
//the error != nil
result(image: nil)
}
}
}
And to call it, you could simply use
imageFromFile(myPFFile){(image: UIImage?) -> Void in
//use the image that was just retrieved
}