web-dev-qa-db-fra.com

Swift 3, URLSession dataTask completionHandler non appelée

Je suis en train d'écrire une bibliothèque, donc je n'utilise pas UIKit. Même dans mon application iOS, le même code fonctionne, mais lorsque j'exécute en ligne de commande, il ne fonctionne pas. En PlayGround aussi, il semble fonctionner.

Pour une raison quelconque, le rappel n'est pas déclenché, les instructions d'impression ne s'exécutent donc pas.

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

Modifications -: J'écris une bibliothèque, je n'utilise donc pas UIKit. Même dans mon application iOS, le même code fonctionne, mais ne fonctionne pas lorsque j'exécute en ligne de commande. En PlayGround aussi, il semble fonctionner.

6
xrage

J'ai fait une application simple à partir de zéro. (Xcode 8 beta 6/Swift 3) Dans le contrôleur, j'ai collé votre code. (plus création d'URL ..) Je vois tout dans le débogueur:

CELUI-CI IS IMPRIME

CELUI-CI IS IMPRIME AUSSI

JE SUIS DE RETOUR

il semble donc travailler.

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

}
9
ingconti

Est-ce que les changements suggérés ici, ça fonctionne maintenant.

Utilisation de NSURLSession à partir d'un programme de ligne de commande 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()
}
4
xrage

Je sais qu'il est tard pour la réponse, mais si vous ne comprenez pas le problème ou si vous ne le rencontrez pas ailleurs, essayons.

Vous devez enregistrer la variable de session en dehors de la méthode (en faire une variable d'instance). Depuis que vous l'avez défini localement dans la portée de la fonction. Son gestionnaire get désalloué avant l'achèvement du processus d'achèvement peut être appelé. N'oubliez pas que le gestionnaire d'achèvement ne peut pas conserver votre objet de session. Après l'exécution de la boucle d'exécution, Garbage Collector désaffectera votre objet de session. Nous devons conserver de tels objets chaque fois que nous voulons être rappelés par des délégués ou par un gestionnaire d'achèvement.

self.session = URLSession(configuration: URLSessionConfiguration.default)
2
Ankit
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()
1
JKLTechnologies