我想将函数作为参数传递,因为我正在处理Web服务,我注意到代码是重复的。
Snippet 1
Service.getAllVouchersUsingCallback() { (response, data, error) -> Void in
guard let statusCode = response?.statusCode else {
Util.showToastWithMessage(Messages.NO_INTERNET_CONNECTION)
return
}
switch statusCode {
case 200:
self.loadVouchersWithData(data!)
case 503:
Util.showToastWithMessage(Messages.SERVICES_NOT_AVAILABLE)
default:
Util.showToastWithMessage(Messages.UNEXPECTED_RESPONSE)
}
}
Snippet 2
Service.getAllCategoriesUsingCallback { (response, data, error) -> Void in
guard let statusCode = response?.statusCode else {
Util.showToastWithMessage(Messages.NO_INTERNET_CONNECTION)
return
}
switch statusCode {
case 200:
self.loadAndGetCategories(data!, withInialText: "Category ")
case 503:
Util.showToastWithMessage(Messages.SERVICES_NOT_AVAILABLE)
default:
Util.showToastWithMessage(Messages.UNEXPECTED_RESPONSE)
}
}
重复的部分是状态代码为nil
时发生的情况,以及响应为200
时我必须执行的操作。我想函数签名应该是这样的:
func dealWithWebServiceResponse(response: NSURLResponse?, withData data: NSData?, whichActionIs action: whateverFunctionType)
所以,我想知道如何传递任何函数,即任意数量的参数或任何数量的返回值,因为在这种情况下我只传递数据,但可能在将来我需要另一种功能
提前致谢。
答案 0 :(得分:3)
探索返回函数的函数是一个很大的问题。所以我们有这段代码:
guard let statusCode = response?.statusCode else {
Util.showToastWithMessage(Messages.NO_INTERNET_CONNECTION)
return
}
switch statusCode {
case 200:
// <<================ Right here, we want to do "something different"
case 503:
Util.showToastWithMessage(Messages.SERVICES_NOT_AVAILABLE)
default:
Util.showToastWithMessage(Messages.UNEXPECTED_RESPONSE)
}
那么我们该如何做和不同的事情?&#34;我们传递一个函数。该功能需要采取&#34;数据&#34;因为这是我们唯一拥有的东西。您可能认为该功能需要&#34;其他事情&#34; (比如&#34;类别&#34;),但它确实没有。 此代码对&#34;类别&#34;一无所知。程序早期的其他东西必须处理那个部分。这里唯一不同的是数据。因此,让我们假装我们拥有该功能一秒钟:
let success: (NSData) -> Void = ...
...
case 200:
success(data!)
...
我们只想弄清楚success
在这种情况下是什么。好吧,在你的第一个例子中,它是:
{ self.loadVouchersWithData($0) }
在你的第二个例子中:
{ self.loadAndGetCategories($0, withInialText: "Category ") }
这两个函数都采用NSData
并且不返回任何内容,就像我们想要的那样。
所以我们想要一种方法来获取第一块代码并插入这个变化的东西。我们想要一个成功的功能&#34;功能并返回一个&#34;处理所有的东西&#34;功能。让我们写出很长的路要走:
func successHandler(success: (NSData) -> Void) -> (NSHTTPURLResponse?, NSData?, NSError?) -> Void {
return { (response: NSHTTPURLResponse?, data: NSData?, error: NSError?) in
guard let statusCode = response?.statusCode else {
Util.showToastWithMessage(Messages.NO_INTERNET_CONNECTION)
return
}
switch statusCode {
case 200:
success(data!) // <==== Here's the part that changes!
case 503:
Util.showToastWithMessage(Messages.SERVICES_NOT_AVAILABLE)
default:
Util.showToastWithMessage(Messages.UNEXPECTED_RESPONSE)
}
}
}
哇,第一行是一个很好的。让我们看一下:
func successHandler(success: (NSData) -> Void) -> (NSHTTPURLResponse?, NSData?, NSError?) -> Void {
这是一个函数,它接受一个接受NSData并且不返回任何内容的函数,并且整个函数返回一个函数,该函数接收响应,数据,错误元组,并且不返回任何内容。冥想一下。你真的希望自己陷入其中,因为它真的非常强大。
好的,希望它开始有点下沉,所以我要继续前进。语法非常庞大,因此Swift为我们提供了一个简化它的好方法,称为currying:
func successHandler(success: (NSData) -> Void)(response: NSHTTPURLResponse?, data: NSData?, error: NSError?) {
guard let statusCode = response?.statusCode else {
Util.showToastWithMessage(Messages.NO_INTERNET_CONNECTION)
return
}
switch statusCode {
case 200:
success(data!) // <==== Here's the part that changes!
case 503:
Util.showToastWithMessage(Messages.SERVICES_NOT_AVAILABLE)
default:
Util.showToastWithMessage(Messages.UNEXPECTED_RESPONSE)
}
}
声明现在是:
func successHandler(success: (NSData) -> Void)(response: NSHTTPURLResponse?, data: NSData?, error: NSError?) {
(我知道这可能看起来并不简单,但确实如此,这肯定会使函数的其余部分变得更简单。)
这与前一个声明(几乎)完全相同。在那条线上调解一下。请注意f(x: T)(y: U)
双括号语法。请注意我可以在最后放置-> Void
。
Currying就像现在传递一些参数一样,以后能够传递其余参数。
好的,我们如何使用它?
Service.getAllVouchersUsingCallback(successHandler{ self.loadVouchersWithData($0) })
Service.getAllCategoriesUsingCallback(successHandler{ self.loadAndGetCategories($0, withInialText: "Category ") })
我们称之为需要(响应,数据,错误)的东西,并将调用successHandler
的结果传递给带有数据的函数。
这应该删除你所谈论的所有重复。这是一个特别复杂的currying版本,因为有很多级别的功能。但它也表明了这项技术的强大程度。
你可能想暂时搁置这一点,然后回到Introduction to Function Currying in Swift之类的简单介绍。然后,当这有意义时,回过头来看。