How to get timeout info from dataTask - ios

I have the following code for requesting data from an external API:
var request = URLRequest(url: myURL!, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 10.0)
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers
let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { data, response, error in
if error != nil {
print(error)
} else {
let httpResponse = response as? HTTPURLResponse
}
})
dataTask.resume()
The timeoutInterval is set to 10.0. But how can I get back info on if the request/session timed out, or how long the request/session took the complete? I will then use that info to determine which function I should call.
Any help is much appreciated!

If the error is not nil then cast error as URLError and check the code is .timeout or not. Here is the code.
var request = URLRequest(url: myURL!, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 10.0)
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers
let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
if (error != nil) {
if let error = error as? URLError {
if error.code == .timedOut {
print("Timeout error")
}
}
print(error)
} else {
let httpResponse = response as? HTTPURLResponse
}
})
dataTask.resume()

Related

HTTP load failed (error code: -1005 [4:-4]) - BUT NOT Alamofire

TIC Read Status [2:0x6040001660c0]: 1:57
<10> HTTP load failed (error code: -1005 [4:-4])
<10> finished with error - code: -1005
I can't figure out this error. There are several threads about this, but they are all about uploading with alamofire. I have alamofire in my app, but not in this view controller and I don't use alamofire for this connection.
The error appears in about 1 out of 20 connection.
Here is my code
URLCache.shared.removeAllCachedResponses() if let requestURL = URL(string: "https://example.com/test.php") {
var urlRequest = URLRequest(url: requestURL)
urlRequest.httpMethod = "POST"
let postString = "task_id=1"
urlRequest.httpBody = postString.data(using: .utf8)
let session = URLSession.shared
let task = session.dataTask(with: urlRequest as URLRequest) { (data, response, error) in
if let data = data {
do {
if let jsonResult = try JSONSerialization.jsonObject(with: data, options: []) as? [String:Any] {
// Async Stuff
DispatchQueue.main.async(execute: {
})
}
} catch {
print("Error: \(error)")
self.errorAction()
}
}
}

URLSession Error Swift 3

I have the following code:
func downloadItems() {
let url: NSURL = NSURL(string: urlPath)!
var session: URLSession!
let configuration = URLSessionConfiguration.default
session = URLSession(configuration: configuration, delegate: self, delegateQueue: nil)
let task = session.dataTask(with: url as URL)
task.resume()
}
This is from an older project online, and Swift is giving me this error code:
'URLSession' produces '()', not the expected contextual result type 'URLSession!'.
I've found other people asking about this on Stock Overflow, but all the answers are for older versions of Swift, and result in other errors.
Here are the other questions I found:
How to set URLSession Swift 3
URLSession error
var request = URLRequest(url: URL(string: urlPath!))
request.httpMethod = "GET"
task1 = URLSession.shared.dataTask(with: request) { data, response, error
in guard let data = data, error == nil else {
// check for fundamental networking error
print("error=\(error)")
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 {
// check for http errors
print("statusCode should be 200, but is \(httpStatus.statusCode)")
print("response = \(response)")
}
let json=JSON(data: data);
self.json=json;
self.parse(json: json)
}
task1.resume()

Function Return value at the Beginning [duplicate]

This question already has answers here:
Returning data from async call in Swift function
(13 answers)
Closed 6 years ago.
When i call this function , function returns value and then doing all other things. How can i make function to return value end of other things.
func register(parameters : [String : String]) -> Int {
let headers = [
"content-type": "application/json",
"cache-control": "no-cache",
]
var statuscode = 0
var postD = NSData();
do {
let postData = try NSJSONSerialization.dataWithJSONObject(parameters, options: NSJSONWritingOptions.PrettyPrinted)
postD = postData;
}catch let error as NSError{
print(error.description)
}
var request = NSMutableURLRequest(URL: NSURL(string: "\(hostUrl)/users")!,
cachePolicy: .UseProtocolCachePolicy,
timeoutInterval: 10.0)
request.HTTPMethod = "POST"
request.allHTTPHeaderFields = headers
request.HTTPBody = postD
let session = NSURLSession.sharedSession()
let dataTask = session.dataTaskWithRequest(request, completionHandler: { (data, response, error) -> Void in
if (error != nil) {
print(error)
} else {
let httpResponse = response as? NSHTTPURLResponse
statuscode = httpResponse!.statusCode
print("AFTER HTTP RESPONSE STATUSCODE = \(statuscode)")
}
})
dataTask.resume()
return statuscode
}
Im calling this function like this :
let statuscode = client.register(parameters)
print("denemeeeeeeeeeeeeee\(statuscode)")
And this is my output
denemeeeeeeeeeeeeee0
AFTER HTTP RESPONSE STATUSCODE = 400
NSURLSession is an asynchronous API, so I'm afraid your function will always return before the data request completes. You'll have to consider alternative approaches. For example your register method could receive a completion closure that you call when your data task is complete.
You need to implement a callback function to handle this kind of stuff:
func register(parameters : [String : String], callback: ((success: Bool, response: NSHTTPURLResponse)->Void){
let headers = [
"content-type": "application/json",
"cache-control": "no-cache",
]
var postD = NSData();
do {
let postData = try NSJSONSerialization.dataWithJSONObject(parameters, options: NSJSONWritingOptions.PrettyPrinted)
postD = postData;
}catch let error as NSError{
print(error.description)
}
var request = NSMutableURLRequest(URL: NSURL(string: "\(hostUrl)/users")!,
cachePolicy: .UseProtocolCachePolicy,
timeoutInterval: 10.0)
request.HTTPMethod = "POST"
request.allHTTPHeaderFields = headers
request.HTTPBody = postD
let session = NSURLSession.sharedSession()
let dataTask = session.dataTaskWithRequest(request, completionHandler: { (data, response, error) -> Void in
if (error != nil) {
print(error)
} else {
let httpResponse = response as? NSHTTPURLResponse
callback?(success: true, response: httpResponse)
}
})
dataTask.resume()
}
and in your function call:
client.register(parameters, callback: { (success, response) in
var statuscode = 0
statuscode = response!.statusCode
print("AFTER HTTP RESPONSE STATUSCODE = \(statuscode)")
})
If this is not enough to achieve what you want to do, you could also look into dispatch groups.
Best of luck.

Swift 3 getURL Ambiguous Data [duplicate]

Hello I have working json parsing code for swift2.2 but when i use it for Swift 3.0 gives me that error
ViewController.swift:132:31: Ambiguous reference to member 'dataTask(with:completionHandler:)'
My code is here:
let listUrlString = "http://bla.com?batchSize=" + String(batchSize) + "&fromIndex=" + String(fromIndex)
let myUrl = URL(string: listUrlString);
let request = NSMutableURLRequest(url:myUrl!);
request.httpMethod = "GET";
let task = URLSession.shared().dataTask(with: request) {
data, response, error in
if error != nil {
print(error!.localizedDescription)
DispatchQueue.main.sync(execute: {
AWLoader.hide()
})
return
}
do {
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSArray
if let parseJSON = json {
var items = self.categoryList
items.append(contentsOf: parseJSON as! [String])
if self.fromIndex < items.count {
self.categoryList = items
self.fromIndex = items.count
DispatchQueue.main.async(execute: {
self.categoriesTableView.reloadData()
AWLoader.hide()
})
}else if( self.fromIndex == items.count){
DispatchQueue.main.async(execute: {
AWLoader.hide()
})
}
}
} catch {
AWLoader.hide()
print(error)
}
}
task.resume()
Thanks for ideas.
The compiler is confused by the function signature. You can fix it like this:
let task = URLSession.shared.dataTask(with: request as URLRequest) {
But, note that we don't have to cast "request" as URLRequest in this signature if it was declared earlier as URLRequest instead of NSMutableURLRequest:
var request = URLRequest(url:myUrl!)
This is the automatic casting between NSMutableURLRequest and the new URLRequest that is failing and which forced us to do this casting here.
You have init'd myRequest as NSMutableURLRequest, you need this:
var URLRequest
Swift is ditching both the NSMutable... thing. Just use var for the new classes.
Xcode 8 and Swift 3.0
Using URLSession:
let url = URL(string:"Download URL")!
let req = NSMutableURLRequest(url:url)
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config, delegate: self, delegateQueue: OperationQueue.main)
let task : URLSessionDownloadTask = session.downloadTask(with: req as URLRequest)
task.resume()
URLSession Delegate call:
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
}
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask,
didWriteData bytesWritten: Int64, totalBytesWritten writ: Int64, totalBytesExpectedToWrite exp: Int64) {
print("downloaded \(100*writ/exp)" as AnyObject)
}
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL){
}
Using Block GET/POST/PUT/DELETE:
let request = NSMutableURLRequest(url: URL(string: "Your API URL here" ,param: param))!,
cachePolicy: .useProtocolCachePolicy,
timeoutInterval:"Your request timeout time in Seconds")
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers as? [String : String]
let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest) {data,response,error in
let httpResponse = response as? HTTPURLResponse
if (error != nil) {
print(error)
} else {
print(httpResponse)
}
DispatchQueue.main.async {
//Update your UI here
}
}
dataTask.resume()
Working fine for me.. try it 100% result guarantee
This problem is caused by URLSession has two dataTask methods
open func dataTask(with request: URLRequest, completionHandler: #escaping (Data?, URLResponse?, Error?) -> Swift.Void) -> URLSessionDataTask
open func dataTask(with url: URL, completionHandler: #escaping (Data?, URLResponse?, Error?) -> Swift.Void) -> URLSessionDataTask
The first one has URLRequest as parameter, and the second one has URL as parameter, so we need to specify which type to call, for example, I want to call the second method
let task = URLSession.shared.dataTask(with: url! as URL) {
data, response, error in
// Handler
}
In my case error was in NSURL
let url = NSURL(string: urlString)
In Swift 3 you must write just URL:
let url = URL(string: urlString)
Tested xcode 8 stable version ; Need to use var request variable with URLRequest() With thats you can easily fix that (bug)
var request = URLRequest(url:myUrl!) And
let task = URLSession.shared().dataTask(with: request as URLRequest) { }
Worked fine ! Thank you guys, i think help many people. !
For Swift 3 and Xcode 8:
var dataTask: URLSessionDataTask?
if let url = URL(string: urlString) {
self.dataTask = URLSession.shared.dataTask(with: url, completionHandler: { (data, response, error) in
if let error = error {
print(error.localizedDescription)
} else if let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 {
// You can use data received.
self.process(data: data as Data?)
}
})
}
}
//Note: You can always use debugger to check error
In swift 3 the compiler is confused by the function signature. Specifying it will clear the error. Also convert the url string to type URL. The following code worked for me.
let urlString = "http://bla.com?batchSize="
let pathURL = URL(string: urlString)!
var urlRequest = URLRequest(url:pathURL)
let session = URLSession.shared
let dataTask = session.dataTask(with: urlRequest as URLRequest) { (data,response,error) in
Short and concise answer for Swift 3:
guard let requestUrl = URL(string: yourURL) else { return }
let request = URLRequest(url:requestUrl)
URLSession.shared.dataTask(with: request) {
(data, response, error) in
...
}.resume()
// prepare json data
let mapDict = [ "1":"First", "2":"Second"]
let json = [ "title":"ABC" , "dict": mapDict ] as [String : Any]
let jsonData : NSData = NSKeyedArchiver.archivedData(withRootObject: json) as NSData
// create post request
let url = NSURL(string: "http://httpbin.org/post")!
let request = NSMutableURLRequest(url: url as URL)
request.httpMethod = "POST"
// insert json data to the request
request.httpBody = jsonData as Data
let task = URLSession.shared.dataTask(with: request as URLRequest){ data,response,error in
if error != nil{
return
}
do {
let result = try JSONSerialization.jsonObject(with: data!, options: []) as? [String:AnyObject]
print("Result",result!)
} catch {
print("Error -> \(error)")
}
}
task.resume()
To load data via a GET request you don't need any URLRequest (and no semicolons)
let listUrlString = "http://bla.com?batchSize=" + String(batchSize) + "&fromIndex=" + String(fromIndex)
let myUrl = URL(string: listUrlString)!
let task = URLSession.shared.dataTask(with: myUrl) { ...
let task = URLSession.shared.dataTask(with: request as URLRequest, completionHandler: { data,response,error in
if error != nil{
print(error!.localizedDescription)
return
}
if let responseJSON = (try? JSONSerialization.jsonObject(with: data!, options: [])) as? [String:AnyObject]{
if let response_token:String = responseJSON["token"] as? String {
print("Singleton Firebase Token : \(response_token)")
completion(response_token)
}
}
})
task.resume()
Xcode 10.1 Swift 4
This worked for me:
let task: URLSessionDataTask = session.dataTask(with: request as URLRequest) { (data, response, error) -> Void in
...
The key was adding in the URLSessionDataTask type declaration.
For me I do this to find,
let url = URL(string: urlString)
URLSession.shared.dataTask(with: url!) { (data, response, error) in ...}
Can't use
"let url = NSURL(string: urlString)

sendAsynchronousRequest was deprecated in iOS 9, How to alter code to fix

Below is my code I am getting the issue with:
func parseFeedForRequest(request: NSURLRequest, callback: (feed: RSSFeed?, error: NSError?) -> Void)
{
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()) { (response, data, error) -> Void in
if ((error) != nil)
{
callback(feed: nil, error: error)
}
else
{
self.callbackClosure = callback
let parser : NSXMLParser = NSXMLParser(data: data!)
parser.delegate = self
parser.shouldResolveExternalEntities = false
parser.parse()
}
}
}
This is now deprecated as of iOS 9, and is telling me to use dataTaskWithRequest instead. Can someone help me change sendAsync with dataTask, I don't know how to.
Use NSURLSession instead like below,
For Objective-C
NSURLSession *session = [NSURLSession sharedSession];
[[session dataTaskWithURL:[NSURL URLWithString:"YOUR URL"]
completionHandler:^(NSData *data,
NSURLResponse *response,
NSError *error) {
// handle response
}] resume];
For Swift,
var request = NSMutableURLRequest(URL: NSURL(string: "YOUR URL")!)
var session = NSURLSession.sharedSession()
request.HTTPMethod = "POST"
var params = ["username":"username", "password":"password"] as Dictionary<String, String>
request.HTTPBody = try? NSJSONSerialization.dataWithJSONObject(params, options: [])
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
var task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
print("Response: \(response)")})
task.resume()
For asynchronously query, from Apple docs
Like most networking APIs, the NSURLSession API is highly
asynchronous. It returns data in one of two ways, depending on the
methods you call:
To a completion handler block that returns data to your app when a
transfer finishes successfully or with an error.
By calling methods on your custom delegate as the data is received.
By calling methods on your custom delegate when download to a file is
complete.
Swift implementation
let session = NSURLSession.sharedSession()
session.dataTaskWithRequest(request) { (data, response, error) -> Void in
}
Swift 3.0
var request = URLRequest(url: URL(string: "http://example.com")!)
request.httpMethod = "POST"
let session = URLSession.shared
session.dataTask(with: request) {data, response, err in
print("Entered the completionHandler")
}.resume()
This is the swift 2.1 version:
let request = NSMutableURLRequest(URL: NSURL(string: "YOUR URL")!)
let session = NSURLSession.sharedSession()
request.HTTPMethod = "POST"
let params = ["username":"username", "password":"password"] as Dictionary<String, String>
request.HTTPBody = try! NSJSONSerialization.dataWithJSONObject(params, options: [])
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
let task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
print("Response: \(response)")})
task.resume()
Swift 2.0:
Old (replace with New below):
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue()) { (response, data, error) -> Void in
// Code
}
New:
let task = NSURLSession.sharedSession().dataTaskWithRequest(request){ data, response, error in
// Code
}
task.resume()
Swift 4
let params = ["email":"email#email.com", "password":"123456"] as Dictionary<String, String>
var request = URLRequest(url: URL(string: "http://localhost:8080/api/1/login")!)
request.httpMethod = "POST"
request.httpBody = try? JSONSerialization.data(withJSONObject: params, options: [])
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
let session = URLSession.shared
let task = session.dataTask(with: request, completionHandler: { data, response, error -> Void in
do {
let json = try JSONSerialization.jsonObject(with: data!) as! Dictionary<String, AnyObject>
print(json)
} catch {
print("error")
}
})
task.resume()
with swift 3.1
let request = NSMutableURLRequest(url: NSURL(string: image_url_string)! as URL)
let session = URLSession.shared
request.httpMethod = "POST"
let params = ["username":"username", "password":"password"] as Dictionary<String, String>
request.httpBody = try? JSONSerialization.data(withJSONObject: params, options: [])
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
let task = session.dataTask(with: request as URLRequest, completionHandler: {data, response, error -> Void in
print("Response: \(String(describing: response))")})
task.resume()
Illustrating with an example, the alternative code to the deprecation of:
sendAsynchronousRequest(_:queue:completionHandler:)' was deprecated in iOS 9.0: Use [NSURLSession dataTaskWithRequest:completionHandler:]
Tested and works in Swift 2.1 onwards.
import UIKit
class ViewController: UIViewController {
#IBOutlet var theImage: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
let url = NSURL(string: "https://upload.wikimedia.org/wikipedia/commons/6/6a/Johann_Sebastian_Bach.jpg")
let task = NSURLSession.sharedSession().dataTaskWithURL(url!) { (data, response, error) -> Void in
if error != nil {
print("thers an error in the log")
} else {
dispatch_async(dispatch_get_main_queue()) {
let image = UIImage(data: data!)
self.theImage.image = image
}
}
}
task.resume()
}
}
//Displays an image on the ViewControllers ImageView. Connect an outlet of the ImageView
Here is the SWIFT3.0 Version of Nilesh Patel's Answer with JSONSerialised data
let url = URL(string: "<HERE GOES SERVER API>")!
var request = URLRequest(url: url)
request.httpMethod = "POST" //GET OR DELETE etc....
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("<ValueforAuthorization>", forHTTPHeaderField: "Authorization")
let parameter = [String:Any]() //This is your parameters [String:Any]
do {
let jsonData = try JSONSerialization.data(withJSONObject: parameter, options: .prettyPrinted)
// here "jsonData" is the dictionary encoded in JSON data
request.httpBody = jsonData
let session = URLSession(configuration: .default)
let task = session.dataTask(with: request, completionHandler: { (incomingData, response, error) in
if let error = error {
print(error.localizedDescription)
print(request)
}else if let response = response {
print(response)
}else if let incomingData = incomingData {
print(incomingData)
}
})
task.resume()
} catch {
print(error.localizedDescription)
}
Swift 4.2
This worked for me:
func loadImageFromURL(URL: NSURL) {
let request = URLRequest(url: URL as URL)
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
if let imageData = data {
DispatchQueue.main.async {
self.imageView.image = UIImage(data: imageData)
}
}
}
task.resume()
}
I had to add "DispatchQueue.main.async { }" because I had a runtime warning, since only the main thread is supposed to modify UI elements.

Resources