如何处理 Swift 中的异步请求?
How do I handle async requests in Swift?
我在我的一个函数中进行了网络服务调用。我在如何构建它时遇到问题,因此逻辑是干净的而不是多余的。这是我拥有的:
public func getTimes() -> [TimeName: MyResult] {
let deferredTask: () -> [TimeName: MyResult] = {
var computed = self.computeTimes()
// Do something
return computed
}
// Calculate timezone
if let tz = timezone {
timeZone = tz
return deferredTask()
} else {
NSURLSession.sharedSession().dataTaskWithURL(NSURL(string: url)!) {
(data, response, error) in
// Do something with data
return deferredTask() // Getting a compiler error here btw: is not convertible to 'Void'
}.resume()
}
}
然后我使用 MyInstance.getTimes()
调用它。不过感觉有些不对劲。设置 deferredTask
变量是避免冗余代码的好方法吗?
此外,当我从另一个函数调用它时,我会使用 var test = MyInstance.getTimes()
。但这意味着 test
处于异步状态,在 getTimes
.
中完成 Web 服务之前,我无法在我的其他函数中使用它
在 Swift 中处理此问题的好方法是什么?
正如您所说,您不能这样做:
public func getTimes() -> [TimeName: MyResult] {
let deferredTask: () -> [TimeName: MyResult] = {
var computed = self.computeTimes()
// Do something
return computed
}
NSURLSession.sharedSession().dataTaskWithURL(NSURL(string: url)!) {
(data, response, error) in
// Do something with data
return deferredTask()
}.resume()
}
正如我认为您正试图说的那样,问题是 return deferredTask()
是 return 来自周围闭包的 - 而不是来自 getTimes
。您不能异步 return 来自函数调用的值!这就是异步的本质。
一个典型的标准解决方案是编写getTimes
本身来接受一个回调函数作为它的参数。它本身 return 没什么。异步方法完成后,它调用回调,从而在将来某个时间将信息返回给原始调用者。
为了向您展示我的意思,我将从故事中完全删除您的 deferredTask
,只专注于异步任务和回调。所以我们会有这个:
public func getTimes(f:(Any) -> Void) -> () {
NSURLSession.sharedSession().dataTaskWithURL(NSURL(string: url)!) {
(data, response, error) in
// ...
f(whatever)
}.resume()
}
这个架构的要点是对 f(whatever)
的调用有效地返回到首先交给我们 f
的人 - 特别是如果那个实体把 self
放到某个地方.
我在我的一个函数中进行了网络服务调用。我在如何构建它时遇到问题,因此逻辑是干净的而不是多余的。这是我拥有的:
public func getTimes() -> [TimeName: MyResult] {
let deferredTask: () -> [TimeName: MyResult] = {
var computed = self.computeTimes()
// Do something
return computed
}
// Calculate timezone
if let tz = timezone {
timeZone = tz
return deferredTask()
} else {
NSURLSession.sharedSession().dataTaskWithURL(NSURL(string: url)!) {
(data, response, error) in
// Do something with data
return deferredTask() // Getting a compiler error here btw: is not convertible to 'Void'
}.resume()
}
}
然后我使用 MyInstance.getTimes()
调用它。不过感觉有些不对劲。设置 deferredTask
变量是避免冗余代码的好方法吗?
此外,当我从另一个函数调用它时,我会使用 var test = MyInstance.getTimes()
。但这意味着 test
处于异步状态,在 getTimes
.
在 Swift 中处理此问题的好方法是什么?
正如您所说,您不能这样做:
public func getTimes() -> [TimeName: MyResult] {
let deferredTask: () -> [TimeName: MyResult] = {
var computed = self.computeTimes()
// Do something
return computed
}
NSURLSession.sharedSession().dataTaskWithURL(NSURL(string: url)!) {
(data, response, error) in
// Do something with data
return deferredTask()
}.resume()
}
正如我认为您正试图说的那样,问题是 return deferredTask()
是 return 来自周围闭包的 - 而不是来自 getTimes
。您不能异步 return 来自函数调用的值!这就是异步的本质。
一个典型的标准解决方案是编写getTimes
本身来接受一个回调函数作为它的参数。它本身 return 没什么。异步方法完成后,它调用回调,从而在将来某个时间将信息返回给原始调用者。
为了向您展示我的意思,我将从故事中完全删除您的 deferredTask
,只专注于异步任务和回调。所以我们会有这个:
public func getTimes(f:(Any) -> Void) -> () {
NSURLSession.sharedSession().dataTaskWithURL(NSURL(string: url)!) {
(data, response, error) in
// ...
f(whatever)
}.resume()
}
这个架构的要点是对 f(whatever)
的调用有效地返回到首先交给我们 f
的人 - 特别是如果那个实体把 self
放到某个地方.