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 был определен как НЕТ.