Swift 闭包与从函数返回值/对象

Swift 闭包与从函数返回值/对象,swift,function,architecture,closures,swift4,Swift,Function,Architecture,Closures,Swift4,我目前正在学习Swift(4)/iOS编程。我对面向对象编程相当陌生,但确实有函数式编程的经验。有一个概念让我有些困惑 在我遵循的课程/示例中,函数主要如下所示: func getUsername(forUid uid: String, handler: @escaping (_ username: String) -> Void) { //Do stuff handler("MyName") } func getUsername(forUid uid: String) ->

我目前正在学习Swift(4)/iOS编程。我对面向对象编程相当陌生,但确实有函数式编程的经验。有一个概念让我有些困惑

在我遵循的课程/示例中,函数主要如下所示:

func getUsername(forUid uid: String, handler: @escaping (_ username: String) -> Void) {
//Do stuff    
handler("MyName")
}
func getUsername(forUid uid: String) -> String) {
//Do stuff    
 return "MyName"
}
名称通过闭包传递,我很少看到这样的函数:

func getUsername(forUid uid: String, handler: @escaping (_ username: String) -> Void) {
//Do stuff    
handler("MyName")
}
func getUsername(forUid uid: String) -> String) {
//Do stuff    
 return "MyName"
}

第二种方法是否已弃用,或者该函数是否仍有使用价值。我们何时以及为什么要使用第一个变体?

当然,它没有被弃用。
您应该为异步任务使用闭包,否则返回值。

通过一个示例更容易获得它。下面是我从API获得的一些位置:

func getPlaces(onSuccess: @escaping(_ places: [Place]?) -> Void, onFailure: @escaping(Error, _ title: String?, _ message: String?) -> Void) {
    //perform API request...
    //[...]
    //...
        // Session
        session.dataTask(with: requestURL) { (data, response, error) in
            guard error == nil else {

                //handling Error
                onFailure(error!, "Error", error?.localizedDescription)
                group.leave()
                return
            }
            //...
            //handling succes
            else {
                var places: [Place] = []

                places = responseJson.places!
                onSuccess(places)
            }
            group.leave()
            }.resume()
    }
    group.wait()
    return
}
正如你所看到的,我想要处理成功和错误。以下是我如何使用它:

APIManager.shared.getPlaces(onSuccess: { (places) in
          //handling success
        }
    }) { (error, title, message) in
        DispatchQueue.main.async {
            self.present(getAlertFromError(title: title, message: message), animated: true)
        }
    }

我们使用第一个变量进行异步编程。例如,请参见

func getUsername(forUid uid: String, handler: @escaping (_ username: String) -> Void) {
    DispatchQueue.main.async {
        // do some asynchronous stuff
        handler("MyName")
    }
}
注意
handler
必须位于
async
闭包内,否则将立即调用该处理程序,因为
async
不阻塞。现在,如果我们使用
return
而不是
handler
,则会出现编译错误,因为您的函数不返回任何值,因此要修复编译错误,它必须位于函数级别(而不是
async
块)。如果它不在
async
块中,它将立即返回(与上面的第二个
handler
案例相同,因此如果您正在执行异步任务,则必须使用闭包。但是,如果您没有使用异步内容,则可以安全地在代码中使用第二个变量


除了异步编程之外,闭包也用于同步编程,例如,函数使用闭包作为参数来定义对象应如何映射。

谢谢。我只是不完全习惯异步编程,因此会产生混淆。但现在清楚了:)@paper1111闭包不限于异步行为。它也可以根据上下文同步运行。异步性的易用性只是闭包的一个应用程序。我刚刚添加了一段关于同步闭包的内容。