Подождите, пока задача загрузки завершится в NSURLSession - программирование
Подтвердить что ты не робот

Подождите, пока задача загрузки завершится в NSURLSession

Мой сценарий выглядит так: у меня есть класс, в котором есть функция, и эта функция делает запрос POST на сервер с NSURLSession. В другой функции, которая не входит в этот класс, я вызываю эту функцию с задачей в ней, которая работает асинхронно, я думаю. Я столкнулся с следующей проблемой: когда я загружаю ответ JSON с сервера и записываю его в переменную и возвращаю ее, переменная, которую я написал, по-прежнему равна нулю, так как она не дождалась завершения потока/задачи и возвращает начальное значение, которое равно нулю.

Итак, мой вопрос: как я могу дождаться завершения этой задачи, а затем продолжить всю программу.

Это мой класс с функцией запроса:

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 после этой задачи.

4b9b3361

Ответ 1

Как я уже говорил в комментариях к основному сообщению, загрузка 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);
}

Это может быть не самое эффективное и не самое элегантное решение, но в моем случае мне действительно нужно было дождаться завершения загрузки, иначе ничего не должно делать.