在 NSURLSession 中等待下载任务完成
Wait for download task to finish in NSURLSession
我的场景是这样的:我有一个 class,其中有一个函数,这个函数向带有 NSURLSession 的服务器发出 POST 请求。在另一个不在 class 中的函数中,我用其中的任务调用该函数,我认为它是异步运行的。我遇到以下问题:当我从服务器下载 JSON 响应并将其写入变量和 return 时,我写入的变量仍然为零,因为它没有等待thread/task 完成下载,return 初始值为 nil。
所以我的问题是如何等待该任务完成然后继续整个程序。
这是我的 class 请求函数:
class DownloadTask {
var json:NSDictionary!
var cookie:String!
var responseString : NSString = ""
func forData(completion: (NSString) -> ()) {
var theJSONData:NSData!
do {
theJSONData = try NSJSONSerialization.dataWithJSONObject(json, options: NSJSONWritingOptions())
} catch _ {
print("error")
}
let request = NSMutableURLRequest(URL: url)
request.HTTPMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
if cookie != nil {
request.setValue(cookie, forHTTPHeaderField: "Cookie")
}
request.HTTPBody = theJSONData
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
if error != nil {
print("error")
return
} else {
completion(NSString(data: data!, encoding: NSUTF8StringEncoding)!)
}
}
task.resume()
}
}
这是我的调用代码:
let task = DownloadTask()
task.forData { jsonString in
do {
if let json: NSDictionary = try NSJSONSerialization.JSONObjectWithData(jsonString.dataUsingEncoding(NSUTF8StringEncoding)!, options: NSJSONReadingOptions.MutableContainers) as? NSDictionary {
if json["error"] != nil {
authenticated = false
} else {
let result = json["result"] as! NSDictionary
user.personId = result["personId"] as! NSNumber
user.sessionId = result["sessionId"] as! NSString
print("test0")
authenticated = true
}
}
}
catch _ {
print("error")
}
}
print("test1")
输出为:
test1
test0
我无法在该任务后访问变量 user.sessionId。
正如我之前在主 post 的评论中所说,下载 NSURLSession.sharedSession().dataTaskWithRequest(request)
运行 同步到主线程,这意味着它将数据同步下载到显示。所以简而言之, print("test0")
将在分派的线程完成时执行(也就是下载数据)。为了解决这个问题,我不得不使用信号量(我还结合了原始问题中的第一个代码和第二个代码):
private func downloadData(completion: (String) -> ()) {
let semaphore = dispatch_semaphore_create(0);
let request = NSMutableURLRequest(URL: url)
var theJSONData = NSData()
do {
theJSONData = try NSJSONSerialization.dataWithJSONObject(json, options: NSJSONWritingOptions())
} catch {
completion(String())
}
request.HTTPMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.HTTPBody = theJSONData
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
data == nil ? completion(String()) : completion(String(data: data!, encoding: NSUTF8StringEncoding)!)
dispatch_semaphore_signal(semaphore);
}
task.resume()
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
}
这可能不是最有效也不是最优雅的解决方案,但就我而言,我真的不得不等待下载完成,否则它不应该做任何事情。
我的场景是这样的:我有一个 class,其中有一个函数,这个函数向带有 NSURLSession 的服务器发出 POST 请求。在另一个不在 class 中的函数中,我用其中的任务调用该函数,我认为它是异步运行的。我遇到以下问题:当我从服务器下载 JSON 响应并将其写入变量和 return 时,我写入的变量仍然为零,因为它没有等待thread/task 完成下载,return 初始值为 nil。
所以我的问题是如何等待该任务完成然后继续整个程序。
这是我的 class 请求函数:
class DownloadTask {
var json:NSDictionary!
var cookie:String!
var responseString : NSString = ""
func forData(completion: (NSString) -> ()) {
var theJSONData:NSData!
do {
theJSONData = try NSJSONSerialization.dataWithJSONObject(json, options: NSJSONWritingOptions())
} catch _ {
print("error")
}
let request = NSMutableURLRequest(URL: url)
request.HTTPMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
if cookie != nil {
request.setValue(cookie, forHTTPHeaderField: "Cookie")
}
request.HTTPBody = theJSONData
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
if error != nil {
print("error")
return
} else {
completion(NSString(data: data!, encoding: NSUTF8StringEncoding)!)
}
}
task.resume()
}
}
这是我的调用代码:
let task = DownloadTask()
task.forData { jsonString in
do {
if let json: NSDictionary = try NSJSONSerialization.JSONObjectWithData(jsonString.dataUsingEncoding(NSUTF8StringEncoding)!, options: NSJSONReadingOptions.MutableContainers) as? NSDictionary {
if json["error"] != nil {
authenticated = false
} else {
let result = json["result"] as! NSDictionary
user.personId = result["personId"] as! NSNumber
user.sessionId = result["sessionId"] as! NSString
print("test0")
authenticated = true
}
}
}
catch _ {
print("error")
}
}
print("test1")
输出为:
test1
test0
我无法在该任务后访问变量 user.sessionId。
正如我之前在主 post 的评论中所说,下载 NSURLSession.sharedSession().dataTaskWithRequest(request)
运行 同步到主线程,这意味着它将数据同步下载到显示。所以简而言之, print("test0")
将在分派的线程完成时执行(也就是下载数据)。为了解决这个问题,我不得不使用信号量(我还结合了原始问题中的第一个代码和第二个代码):
private func downloadData(completion: (String) -> ()) {
let semaphore = dispatch_semaphore_create(0);
let request = NSMutableURLRequest(URL: url)
var theJSONData = NSData()
do {
theJSONData = try NSJSONSerialization.dataWithJSONObject(json, options: NSJSONWritingOptions())
} catch {
completion(String())
}
request.HTTPMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.HTTPBody = theJSONData
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
data == nil ? completion(String()) : completion(String(data: data!, encoding: NSUTF8StringEncoding)!)
dispatch_semaphore_signal(semaphore);
}
task.resume()
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
}
这可能不是最有效也不是最优雅的解决方案,但就我而言,我真的不得不等待下载完成,否则它不应该做任何事情。