从包含闭包的Swift函数返回一个值

时间:2015-09-24 10:06:14

标签: ios swift function completionhandler

我编写了一个应该返回一个值的函数,但该值来自一个闭包。问题是如果我尝试从闭包内部返回一个值,它会将其视为完成处理程序的返回值。

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)")
        }
    })
}

1 个答案:

答案 0 :(得分:0)

在您的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中对它进行了测试,它可以正常运行:

enter image description here