从包含闭包的 Swift 函数返回值
Posted
技术标签:
【中文标题】从包含闭包的 Swift 函数返回值【英文标题】:Returning a value from a Swift function containing a closure 【发布时间】:2015-09-24 10:06:13 【问题描述】:我编写了一个应该返回值但该值来自闭包的函数。问题是如果我尝试从闭包内部返回一个值,它会将其视为完成处理程序的返回值。
private func loadData() throws -> [Item]
var items = [Item]()
let jsonUrl = "http://api.openweathermap.org/data/2.5/forecast/daily?units=metric&cnt=7&q=coventry,uk"
print(jsonUrl)
let session = NSURLSession.sharedSession()
guard let shotsUrl = NSURL(string: jsonUrl) else
throw JSONError.InvalidURL(jsonUrl)
session.dataTaskWithURL(shotsUrl, completionHandler: (data, response, error) -> Void in
do
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: [])
print(json)
guard let days:[AnyObject] = (json["list"] as! [AnyObject]) else
throw JSONError.InvalidArray
for day in days
guard let timestamp:Double = day["dt"] as? Double else
throw JSONError.InvalidKey("dt")
print(timestamp)
let date = NSDate(timeIntervalSince1970: NSTimeInterval(timestamp))
guard let weather:[AnyObject] = day["weather"] as? [AnyObject] else
throw JSONError.InvalidArray
guard let desc:String = weather[0]["description"] as? String else
throw JSONError.InvalidKey("description")
guard let icon:String = weather[0]["icon"] as? String else
throw JSONError.InvalidKey("icon")
guard let url = NSURL(string: "http://openweathermap.org/img/w/\(icon).png") else
throw JSONError.InvalidURL("http://openweathermap.org/img/w/\(icon).png")
guard let data = NSData(contentsOfURL: url) else
throw JSONError.InvalidData
guard let image = UIImage(data: data) else
throw JSONError.InvalidImage
guard let temp:AnyObject = day["temp"] else
throw JSONError.InvalidKey("temp")
guard let max:Float = temp["max"] as? Float else
throw JSONError.InvalidKey("max")
let newDay = Item(date: date, description: desc, maxTemp: max, icon: image)
print(newDay)
items.append(newDay)
return items // this line fails because I'm in the closure. I want this to be the value returned by the loadData() function.
catch
print("Fetch failed: \((error as NSError).localizedDescription)")
)
【问题讨论】:
您可以将闭包作为回调或完成处理程序传递,您可以在要返回项目的地方调用它们。你需要写下你愿意如何处理传递给 loadData() 函数的闭包中的数据。 【参考方案1】:将完成处理程序(在我的示例中名为 dataHandler
)添加到您的 loadData
函数:
private func loadData(dataHandler: ([Item])->()) throws
var items = [Item]()
let jsonUrl = "http://api.openweathermap.org/data/2.5/forecast/daily?units=metric&cnt=7&q=coventry,uk"
print(jsonUrl)
let session = NSURLSession.sharedSession()
guard let shotsUrl = NSURL(string: jsonUrl) else
throw JSONError.InvalidURL(jsonUrl)
session.dataTaskWithURL(shotsUrl, completionHandler: (data, response, error) -> Void in
do
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: [])
print(json)
guard let days:[AnyObject] = (json["list"] as! [AnyObject]) else
throw JSONError.InvalidArray
for day in days
guard let timestamp:Double = day["dt"] as? Double else
throw JSONError.InvalidKey("dt")
print(timestamp)
let date = NSDate(timeIntervalSince1970: NSTimeInterval(timestamp))
guard let weather:[AnyObject] = day["weather"] as? [AnyObject] else
throw JSONError.InvalidArray
guard let desc:String = weather[0]["description"] as? String else
throw JSONError.InvalidKey("description")
guard let icon:String = weather[0]["icon"] as? String else
throw JSONError.InvalidKey("icon")
guard let url = NSURL(string: "http://openweathermap.org/img/w/\(icon).png") else
throw JSONError.InvalidURL("http://openweathermap.org/img/w/\(icon).png")
guard let data = NSData(contentsOfURL: url) else
throw JSONError.InvalidData
guard let image = UIImage(data: data) else
throw JSONError.InvalidImage
guard let temp:AnyObject = day["temp"] else
throw JSONError.InvalidKey("temp")
guard let max:Float = temp["max"] as? Float else
throw JSONError.InvalidKey("max")
let newDay = Item(date: date, description: desc, maxTemp: max, icon: image)
print(newDay)
items.append(newDay)
dataHandler(items)
catch
print("Fetch failed: \((error as NSError).localizedDescription)")
).resume()
do
try loadData itemsArray in
print(itemsArray)
catch
print(error)
我已经在 Playground 中对其进行了测试,它可以正常工作:
【讨论】:
答案应该有效,但它会在操场上引发运行时错误(即使包括结构和错误枚举)。然后我尝试在一个类中公开该方法并从我的视图控制器中调用它。没有错误,但 session.dataTaskWithURL 回调无法运行。 我添加了我的 Playground 运行我的答案没有错误的屏幕截图。请看一看。 // 不要忘记,为了在 Playground 中运行异步代码,您需要启用XCPSetExecutionShouldContinueIndefinitely
! :)
抱歉,忘记添加 XCPSetExecutionShouldContinueIndefinitely(true)以上是关于从包含闭包的 Swift 函数返回值的主要内容,如果未能解决你的问题,请参考以下文章
求助关于 swift 数组,NSArray 和 闭包 的问题