我创建了一个自定义DataManager类。在其中我想要获取方法中的数据并返回NSData对象以便之后转换为JSON。
我试图使用completionHandler获取数据,但没有运气:
class func fetchData() -> NSData? {
var session = NSURLSession.sharedSession(),
result = NSData?()
let DataURL : NSURL = NSURL(string: "http://...file.json")!
let sessionTask = session.dataTaskWithURL(DataURL, completionHandler: { (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void in
result = data
})
sessionTask.resume()
return result
}
提前致谢
答案 0 :(得分:0)
dataTaskWithURL
以异步方式运行。这意味着从completionHandler
返回时不会调用fetchData
闭包。因此,result
尚未设置。
因此,您不应尝试从异步方法同步检索数据。相反,您应该自己使用异步完成处理程序模式:
class func fetchData(completionHandler: (NSData?, NSError?) -> ()) {
let session = NSURLSession.sharedSession()
let dataURL = NSURL(string: "http://...file.json")!
let sessionTask = session.dataTaskWithURL(dataURL) { data, response, error in
completionHandler(data, error)
}
sessionTask.resume()
}
你会这样称呼它:
MyClass.fetchData() { data, error in
if data == nil {
println("\(error)")
} else {
// use `data` here
}
}
// but do not try to use `data` here
顺便说一句,虽然上面解决了你的问题,但是当人们使用这种模式时,他们通常会想要用响应来更新UI,或者更新一些模型对象或者你有什么。但是completionHandler
的{{1}}不会在主线程上运行。因此,很多人会将dataTaskWithURL
的上述实现扩展为始终将fetchData
发送回主队列:
completionHandler
现在,当你调用它时,你可以安全地更新模型对象和/或UI,知道这将在主线程上发生:
class func fetchData(completionHandler: (NSData?, NSError?) -> ()) {
let session = NSURLSession.sharedSession()
let dataURL = NSURL(string: "http://...file.json")!
let sessionTask = session.dataTaskWithURL(dataURL) { data, response, error in
dispatch_async(dispatch_get_main_queue()) {
completionHandler(data, error)
}
}
sessionTask.resume()
}
不可否认,您可能并不总是希望在主线程上运行此完成块,但通常除非执行极其计算密集的操作,否则上述操作非常常见。