在NSURLSession中等待下载任务完成。

时间:2022-09-02 02:20:07

My scenario looks like this: I have a class which has a function in it and this function makes a POST request to a server with NSURLSession. In another function which is not in that class I call that function with the task in it, which runs asynchronously I think. I'm encountering following problem: When I download the JSON response from the server and write it to a variable and return it, the variable I've written to is still nil since it didn't wait for the thread/task to finish downloading and returns the initial value which is nil.

我的场景是这样的:我有一个类,其中有一个函数,这个函数向一个有NSURLSession的服务器发出POST请求。在另一个不在类中的函数中,我调用这个函数,其中包含任务,我认为它是异步运行的。我遇到了以下问题:当我从服务器下载JSON响应并将其写入一个变量并返回时,我写入的变量仍然为nil,因为它没有等待线程/任务完成下载并返回初始值nil。

So my question is how can I wait for that task to finish and then continue the whole program.

所以我的问题是,我该如何等待这项任务完成,然后继续整个计划。

This is my class with the request function:

这是我的类请求函数:

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

}

}

And this is my calling code:

这是我的电话号码:

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

The output is:

的输出是:

test1
test0

And I can't acess the variables user.sessionId after that task.

我不能接受变量用户。sessionId之后的任务。

1 个解决方案

#1


11  

As I said before in the comments of the main post the download NSURLSession.sharedSession().dataTaskWithRequest(request) run synchronously to the main thread which means it downloads the data synchronously to the displaying. So in short the print("test0") will be executed when the dispatched thread is finished (aka downloaded the data). To fix this I had to use semaphores (I also combined the first code and the second code from the original question):

正如我在主贴子的评论中所说,下载NSURLSession.sharedSession(). datataskwithrequest (request)与主线程同步运行,这意味着它将数据同步下载到显示。因此,简而言之,当分派的线程完成(即下载数据)时,将执行打印(“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);
}

This may not be the most efficient nor the most elegant solution but in my case I really had to wait for the downloading to be finished else it shouldn't do anything.

这可能不是最高效、最优雅的解决方案,但在我的情况下,我不得不等待下载完成,否则它不应该做任何事情。

#1


11  

As I said before in the comments of the main post the download NSURLSession.sharedSession().dataTaskWithRequest(request) run synchronously to the main thread which means it downloads the data synchronously to the displaying. So in short the print("test0") will be executed when the dispatched thread is finished (aka downloaded the data). To fix this I had to use semaphores (I also combined the first code and the second code from the original question):

正如我在主贴子的评论中所说,下载NSURLSession.sharedSession(). datataskwithrequest (request)与主线程同步运行,这意味着它将数据同步下载到显示。因此,简而言之,当分派的线程完成(即下载数据)时,将执行打印(“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);
}

This may not be the most efficient nor the most elegant solution but in my case I really had to wait for the downloading to be finished else it shouldn't do anything.

这可能不是最高效、最优雅的解决方案,但在我的情况下,我不得不等待下载完成,否则它不应该做任何事情。