Swift 3, URLSession dataTask завершение Handler не вызывается

Я пишу библиотеку, поэтому не использую UIKit, даже в моем приложении для iOS тот же код работает, но когда я выполняю в командной строке, это не так. В PlayGround тоже вроде работает.

По какой-то причине обратный вызов не запускается, поэтому операторы print не выполняются.

internal class func post(request: URLRequest, responseCallback: @escaping (Bool, AnyObject?) -> ()) {
    execTask(request: request, taskCallback: { (status, resp)  -> Void in
            responseCallback(status, resp)
    })
}

internal class func clientURLRequest(url: URL, path: String, method: RequestMethod.RawValue,  params: Dictionary<String, Any>? = nil) -> URLRequest {
    var request = URLRequest(url: url)
    request.httpMethod = method
    do {
        let jsonData = try JSONSerialization.data(withJSONObject: (params! as [String : Any]), options: .prettyPrinted)

        request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
        request.httpBody = jsonData
    } catch let error as NSError {
        print(error)
    }
    return request
}

private class func execTask(request: URLRequest, taskCallback: @escaping (Bool,
    AnyObject?) -> ()) {

    let session = URLSession(configuration: URLSessionConfiguration.default)
    print("THIS LINE IS PRINTED")
    let task = session.dataTask(with: request, completionHandler: {(data, response, error) -> Void in
        if let data = data {
            print("THIS ONE IS NOT PRINTED")
            let json = try? JSONSerialization.jsonObject(with: data, options: [])
            if let response = response as? HTTPURLResponse , 200...299 ~= response.statusCode {
                taskCallback(true, json as AnyObject?)
            } else {
                taskCallback(false, json as AnyObject?)
            }
        }
    })
    task.resume()
}

Редактирует -: я пишу библиотеку, поэтому не использую UIKit, даже в моем приложении для iOS тот же код работает, но когда я выполняю в командной строке, это не так. В PlayGround тоже вроде работает.

6 ответов

Я сделал простое приложение с нуля. (Xcode 8 beta 6 / swift 3) В контроллер я вставил Ваш код. (плюс создание URL..) Я вижу все в отладчике:

ЭТО ОДИН ПЕЧАТАН

ЭТО ОДИН ПЕЧАТАН, ТОО

Я ВЕРНУЛСЯ

так что похоже работаю.

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let URLString = "https://apple.com"
        let url = URL(string: URLString)
        let request = URLRequest(url: url!)


        ViewController.execTask(request: request) { (ok, obj) in

            print("I AM BACK")

        }

    }

    private class func execTask(request: URLRequest, taskCallback: @escaping (Bool,
        AnyObject?) -> ()) {

        let session = URLSession(configuration: URLSessionConfiguration.default)
        print("THIS LINE IS PRINTED")
        let task = session.dataTask(with: request, completionHandler: {(data, response, error) -> Void in
            if let data = data {
                print("THIS ONE IS PRINTED, TOO")
                let json = try? JSONSerialization.jsonObject(with: data, options: [])
                if let response = response as? HTTPURLResponse , 200...299 ~= response.statusCode {
                    taskCallback(true, json as AnyObject?)
                } else {
                    taskCallback(false, json as AnyObject?)
                }
            }
        })
        task.resume()
    }

}

Я знаю, что уже поздно для ответа, но если вы не выяснили проблему или не получили проблему в других местах, давайте попробуем это.

Вам необходимо сохранить переменную сеанса вне области действия метода (сделать ее переменной экземпляра). Так как вы определили это локально в области действия функции. Его get освобождается до вызова обработчика завершения, помните, что обработчик завершения не может сохранить ваш объект сеанса, и после выполнения цикла выполнения сборщик мусора освободит ваш объект сеанса. Нам нужно сохранять такие объекты всякий раз, когда мы хотим перезвонить от делегатов или от обработчика завершения.

self.session = URLSession(configuration: URLSessionConfiguration.default)

Сделал изменения, предложенные здесь, это работает сейчас.

Использование NSURLSession из программы командной строки Swift

var sema = DispatchSemaphore( value: 0 )

private func execTask(request: URLRequest, taskCallback: @escaping (Bool,
    AnyObject?) -> ()) {

    let session = URLSession(configuration: URLSessionConfiguration.default, delegate: self, delegateQueue: nil )

    session.dataTask(with: request) {(data, response, error) -> Void in
        if let data = data {
            let json = try? JSONSerialization.jsonObject(with: data, options: [])
            if let response = response as? HTTPURLResponse , 200...299 ~= response.statusCode {
                taskCallback(true, json as AnyObject?)
            } else {
                taskCallback(false, json as AnyObject?)
            }
        }
    }.resume()
    sema.wait()
}
let dataTask = session.dataTask(with: request, completionHandler: {data, response,error -> Void in 
    print("Request : \(response)")

    let res = response as! HTTPURLResponse

    print("Status Code : \(res.statusCode)")

    let strResponse = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
    print("Response String :\(strResponse)")
    })
dataTask.resume()

Swift 3.0

Просто скопируйте приведенный ниже код в свой контроллер вида.

@IBAction func btnNewApplicationPressed (_ sender: UIButton) {
        callWebService()
}

func callWebService() {
    // Show MBProgressHUD Here
    var config                              :URLSessionConfiguration!
    var urlSession                          :URLSession!

    config = URLSessionConfiguration.default
    urlSession = URLSession(configuration: config)

    // MARK:- HeaderField
    let HTTPHeaderField_ContentType         = "Content-Type"

    // MARK:- ContentType
    let ContentType_ApplicationJson         = "application/json"

    //MARK: HTTPMethod
    let HTTPMethod_Get                      = "GET"

    let callURL = URL.init(string: "https://itunes.apple.com/in/rss/newapplications/limit=10/json")

    var request = URLRequest.init(url: callURL!)

    request.timeoutInterval = 60.0 // TimeoutInterval in Second
    request.cachePolicy = URLRequest.CachePolicy.reloadIgnoringLocalCacheData
    request.addValue(ContentType_ApplicationJson, forHTTPHeaderField: HTTPHeaderField_ContentType)
    request.httpMethod = HTTPMethod_Get

    let dataTask = urlSession.dataTask(with: request) { (data,response,error) in
        if error != nil{
            return
        }
        do {
            let resultJson = try JSONSerialization.jsonObject(with: data!, options: []) as? [String:AnyObject]
            print("Result",resultJson!)
        } catch {
            print("Error -> \(error)")
        }
    }

    dataTask.resume()
}

Иногда, для меня, решение, когда завершение Handler не вызывалось в этих случаях, состояло в том, что флаг "Разрешить произвольные загрузки" в Info.plist был определен как НЕТ.

Флаг Разрешить произвольные загрузки, определенный как ДА

Другие вопросы по тегам