iOS - Swift - 返回异步检索值的函数

时间:2015-08-03 18:44:33

标签: ios swift asynchronous parse-platform

所以我有一个来自Parse的PFFile对象,我正在尝试创建一个函数来检索该PFFile的UIImage表示并返回它。类似的东西:

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
}

然而,这里的问题是显而易见的。因为getDataInBackroundWithBlock函数是异步的,所以我每次都会得到nil。有没有办法等到在返回图像变量之前检索到UIImage?我不知道在这种情况下使用同步getData()是否是一种有效的方法。

3 个答案:

答案 0 :(得分:14)

是的,可以这样做。它被称为closure,或更常见的是callbackcallback本质上是一个函数,可以在另一个函数中用作参数。参数的语法是

functionName: (arg0, arg1, arg2, ...) -> ReturnType

ReturnType通常是Void。在您的情况下,您可以使用

result: (image: UIImage?) -> Void

调用带有一个回调函数的语法是

function(arg0, arg1, arg2, ...){(callbackArguments) -> CallbackReturnType in
    //code
}

调用具有多个回调的函数的语法是(缩进以使其更易于阅读)

function(
    arg0, 
    arg1,
    arg2,
    {(cb1Args) -> CB1Return in /*code*/},
    {(cb2Args) -> CB2Return in /*code*/},
    {(cb3Args) -> CB3Return in /*code*/}
)

如果函数转义函数(在函数返回后调用),则必须在参数类型前添加@escaping

您将要使用在函数返回后调用的单个回调,并且结果包含UIImage?

所以,你的代码可能看起来像这样

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)
        }
    }
}

要打电话,你可以简单地使用

imageFromFile(myPFFile){(image: UIImage?) -> Void in
    //use the image that was just retrieved
}

答案 1 :(得分:3)

您想要的正是承诺/未来设计模式的作用。 Swift中有很多实现。我将以优秀的BrightFutures库为例。 (https://github.com/Thomvis/BrightFutures

这里是代码:

func imageFromFile(file: PFFile) -> Future<UIImage> {
    let promise = Promise<UIImage>()

    file.getDataInBackgroundWithBlock() { (data: NSData?, error: NSError?) -> Void in
        if error != nil {
            image = UIImage(data: data!)

            // As soon as the method completes this will be called
            // and triggers the future.onSuccess in the caller.
            promise.success(image)

        } else {

            // This would trigger future.onFailure in the caller
            promise.failure(error)
        }
    }

    return promise.future
}

说明:你基本上做的是创造一个&#34;承诺&#34;在&#34;未来&#34;将会有结果。在异步方法完成之前,您将立即返回此未来承诺。

此方法的调用者将按如下方式处理:

func doSomethingWithTheImage() {
    let future = imageFromFile(file: pffile)

    future.onSuccess { image in
        // do something with UIImage: image
    }

    future.onFailure { error in
        // handle NSError: error
    }
}

在onSuccess处理程序中,您正在使用成功下载的图像执行所有操作。如果出现错误,则在onFailure处理程序中处理它。

这解决了返回&#34; nil&#34;并且也是处理异步过程的最佳实践之一。

答案 2 :(得分:1)

我不推荐这个

我为Swift 2.0编写了一个小型库,它可以在同步和异步方法之间进行转换,这就是你要求的。它可以找到here。请务必阅读免责声明,该声明解释了在哪些情况下可以使用它(很可能不适用于您的情况)

您可以像这样使用它:

func imageFromFile(file: PFFile) throws -> UIImage? {
    let syncGet = toSync(file.getDataInBackgroundWithBlock)
    let data = try syncGet()
    return data.map(UIImage.init)
}