指定完成处理程序的更短方法
Posted
技术标签:
【中文标题】指定完成处理程序的更短方法【英文标题】:Shorter ways to specify completion handler 【发布时间】:2016-02-20 13:08:29 【问题描述】:我已经遇到过几次这个问题了,所以我想联系一下。
我有许多网络接口负责进行异步网络调用,每个接口中大约有 5/6 个函数都使用具有相同定义的完成处理程序:
(success: Bool, resources: [String: AnyObject] -> Void)
我正在寻找一种替代方法来将它添加到每个函数的末尾,因为它强制每个函数声明到 2/3 行。例如
func performSomeNetworkCall(withThisParam parm1: AnyObject, param2: AnyObject, completion: (success: Bool, resources: [String: AnyObject] -> Void))
关于如何解决长声明问题和重写每个函数的完成定义,我有几个想法。
想一想
使用typealias
来定义闭包,如下所示:
typealias CompletionHandler = (success: Bool, resources: [String: AnyObject] -> Void)?
理论上,这解决了这两个问题,因为它可以快速编写并解决代码长度问题。但是,当从外部源调用函数时,typealias
不会像常规闭包那样自动完成,这意味着您必须每次都将其写出来,从而导致错误。
思想二
使用代码 sn-p(当 Xcode 真正记住你设置它们时)。这在理论上也是有效的,只要所有其他开发代码的开发人员也有相同的代码 sn-p 并且它知道它而不是编写整个声明。
三思
我想过将完成处理程序定义为一个函数并将该函数作为参数传递,如下所示:
func completionHandler() -> (success: Bool, resources: [String: AnyObject] -> Void)
return completionHandler()
但无法实现我想要的。
编辑
我希望通过第三个想法实现的目标
func completionHandler() -> ((success: Bool, resources: [String: AnyObject]) -> Void)
return completionHandler()
func networkCall(completion: (success: Bool, resources: [String: AnyObject]) -> Void)
let request = NSURLRequest(URL: NSURL(string: "http://www.google.co.uk")!)
let session = NSURLSession.sharedSession()
session.dataTaskWithRequest(request) (data, response, error) -> Void in
let handler = completionHandler()
handler(success: true, resources: [String: AnyObject]())
func foo()
let handler = completionHandler()
networkCall(handler)
print(handler)
// hope to use handler.success || handler.resources here
虽然目前只是卡在了 completionHandler 方法调用上——(指出显而易见的......)
【问题讨论】:
我的第一直觉会被认为是三个。不知道为什么这不起作用?你没有达到什么目标?是错误还是没有按您预期的方式工作? @AtheistP3ace 我已经编辑了这个问题,以扩展我希望通过思想三实现的目标。目前它只是在completionHandler()
调用上循环。在尝试使用 foo()
中的处理程序时,我也没有从 Xcode 得到任何建议。例如不建议handler.success
【参考方案1】:
typealias
是解决此问题的典型解决方案。即使在原始定义的文件之外,它也应该自动完成。我认为问题在于您对typealias
的定义。如果你这样定义(注意括号,没有可选的):
typealias CompletionHandler = (success: Bool, resources: [String: AnyObject]) -> Void
func performSomeNetworkCall(withThisParam parm1: AnyObject, param2: AnyObject, completion: CompletionHandler?)
// Implementation
然后自动完成它的工作方式如下:
按回车键后:
【讨论】:
【参考方案2】:我正在寻找替代方案
恕我直言,编写更简洁代码的更好选择是使用“Promises”或“Futures”。这些还不是 Swift 标准库的一部分,但其他语言确实有一种或另一种实现 - 并且已经有 Swift 的第三方库。
例如,使用“类 Scala”Futures,您的代码可能如下所示:
func performSomeNetworkCall(
withThisParam parm1: AnyObject,
param2: AnyObject)
-> Future<[String: AnyObject]>
因此,异步函数返回一个Future,而不是完成处理程序。 future 是一个泛型类,其类型参数等于计算值。如果底层异步函数失败,未来也可能表示错误。
您可以通过 combinator 函数注册一个延续来获得最终结果:
let future = performSomeNetworkCall(param1, param2: param2)
future.map computedValue in
print("Result: \(computedValue)")
.onFailure error in
print("Error: \(error)")
这里,map
是一个 combinator 函数,我们可以使用它注册一个 continuation。组合器根据其延续的返回值返回一个新的未来,因此我们可以组合执行更复杂任务的未来。
当future 成功完成时,将调用延续函数。它通过底层异步函数的 value 作为其参数。延续返回一个值或Void
。
另一个组合器是flatMap
。与map
不同,它的延续只是返回另一个未来:
login().flatMap token in
fetchUser(id: userId).map user in
print("User: \(user)")
.onFailure error in
print("Error: \(error)")
函数login
是一个异步函数。成功完成后,它继续调用异步函数fetchUser
。当fetchUser
成功完成后,打印获取到的用户对象。
如果发生任何故障,错误将传播到已在onFailure
注册的“故障处理程序”。
【讨论】:
这是一个非常有趣的概念,当然是“我正在寻找替代方案”,我没想到会这样,所以谢谢!你能推荐一个第三方库吗?我在 Google 搜索中看到了几个不同的选项。 @Ollie 对于类似 Skala 的期货,有 Thomas Visser 的 BrightFutures - 非常完整和高质量。然后是 Tuomas Kareinen 的 MiniFuture,简约但正确且高质量的代码。我自己的尝试:FutureLib。这可与 BrightFutures 相媲美,但具有更灵活的取消和更灵活的关于抛出延续的 API 和更强大的执行上下文。还有其他库——基于 Objective-C。以上是关于指定完成处理程序的更短方法的主要内容,如果未能解决你的问题,请参考以下文章