I am writing a library, So not using UIKit, Even in my iOS app same code works, but when i execute in command line in doesn't . In PlayGround also it seems working.
For some reason callback is not getting triggered, so print statements are not executing.
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()
}
Edits -: I am writing a library, So not using UIKit, Even in my iOS app same code works, but when i execute in command line in doesn't . In PlayGround also it seems working.
I made a simple App from scratch. (Xcode 8 beta 6 / swift 3)
In controller I pasted Your code. (plus url creation..)
I see all in debugger:
THIS ONE IS PRINTED
THIS ONE IS PRINTED, TOO
I AM BACK
so it seems workin.
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()
}
}
Did the changes suggested here, It works now.
Using NSURLSession from a Swift command line program
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()
}
I know its late for the answer but in case you have not figure out the issue or getting issue at other places, lets try this.
You need to save session variable outside method scope (make it a instance variable). Since you defined it locally in function scope. Its get deallocated before completion handler can be called, remember completion handler can't retain your session object and after execution of run loop, garbage collector will dealloc your session object. We need to retain such objects whenever we want call back from delegates or from completion handler..
self.session = URLSession(configuration: URLSessionConfiguration.default)
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
Just copy below code into your view controller.
@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()
}
Sometimes, for me, the solution when completionHandler were not called in these cases was because the flag "Allow Arbitrary loads" on Info.plist was defined as NO.
Allow Arbitrary loads flag defined as YES