I'm trying to set a client-side timeout per request for Alamofire for Swift. The lead architect told me to set this on NSURLRequest, but I'm completely confused on how to actually do that in practice.
Can someone who has done this give an example? Thanks!
I think this code may works.
var alamofireManager : Alamofire.Manager?
func some(){
let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
configuration.timeoutIntervalForResource = 2 // seconds
self.alamofireManager = Alamofire.Manager(configuration: configuration)
self.alamofireManager!.request(.GET, "http://example.com/")
.response { (request, response, data, error) in
}
}
This is how you can use a per-request timeout using URLRequest:
Alamofire.request(URLRequest(url: ..., cachePolicy: ..., timeoutInterval: 10))
.response(...)
Related
I am sending data to api using the post method. But while working in advance, I have now moved my server to the windows sdd server and started to get the problem I wrote below all the time. While working on Similator, it doesn't work when I try it on my physical phone, I get this problem. What is the problem? A situation related to the firewall? Because I started to get this problem after moving the server. Or another problem?
NSErrorFailingURLStringKey=....php, NSErrorFailingURLKey=....php,
_kCFStreamErrorDomainKey=4, _kCFStreamErrorCodeKey=-2102, NSLocalizedDescription=The request timed out.}
#objc func veriGonder() {
let url = NSURL(string: "...php")
var request = URLRequest(url: url! as URL)
request.httpMethod = "POST"
...
dataString = dataString + "&formCLASSNAMESTARIH\(verıTURUSTarih)"
dataString = dataString + "&formCLASSNAMESZAMAN\(verıTURUsZaman)"
...
let dataD = dataString.data(using: .utf8)
do {
let uploadJob = URLSession.shared.uploadTask(with: request, from: dataD)
{
data, response, error in
...
}
Here as the error specifies your request timed out. So to fix this either you need to increase the timeout interval or increase the server response interval from server-side. So, if it's the first option here's the code you need:
request.timeoutInterval = 100 // increase this to your desired value.
Can this image download technique use timeouts: Why doesn't image load on main thread??
Or must I use NSURLSession instead if I want to use timeouts?
You are looking for the timeoutintervalForResource property. If you use URLSession.shared, the default timeout is 7 days. If you want to use a different timeout, you need to create your own session:
let config = URLSessionConfiguration.default
config.timeoutIntervalForResource = 60 // timeout, in seconds
// A 20 MB image from NASA
let url = URL(string: "https://www.nasa.gov/sites/default/files/thumbnails/image/hs-2015-02-a-hires_jpg.jpg")!
let session = URLSession(configuration: config)
session.dataTask(with: url) { data, response, error in
if let error = error {
print(error)
}
// do something
}.resume()
Lower the timeout enough and you will see a timeout error. Note that URLSessionConfiguration has 2 timeouts: timeoutIntervalForResource and timeoutIntervalForRequest:
...Resource is the time to wait for whole network operation to finish (default is 7 days)
...Request is the time to wait for next chunk of data to arrive (default is 60 seconds)
If your goal is to download something in x minutes, using ...Resource. If your goal is "network must response within x seconds or it's down", use ...Request.
No, you don't have to use NSURLSession. The timeout properties are in URLSesssionConfiguration and you just need to create an instance of URLSession using your desired configuration.
So, rather than using URLSession.shared directly you would need to make your own instance of URLSession and start the dataTask from that instance.
You are probably interested in timeoutIntervalForResource, which I think defaults to 7 days.
Here is a relevant Swift fragment from the answer to this question:
let sessionConfig = URLSessionConfiguration.default
sessionConfig.timeoutIntervalForRequest = 30.0
sessionConfig.timeoutIntervalForResource = 60.0
let session = URLSession(configuration: sessionConfig)
I know how to make a regular API call using swift. What I am not able to understand is how to make the API call to be repeated until required.
I want to call the API every one second
API Call Code Snippet:
let url = URL(string: "https://api.darksky.net/forecast/34eaef38915078ea03c22bb9063bd7ea/37.8267,-122.4233")
let request = URLRequest(url: url!, cachePolicy: URLRequest.CachePolicy.reloadIgnoringCacheData, timeoutInterval: 10)
let session = URLSession(configuration: URLSessionConfiguration.default, delegate: nil, delegateQueue: OperationQueue.main)
let task: URLSessionDataTask = session.dataTask(with: request, completionHandler: { (data: Data?, response: URLResponse?, error: Error?) in
if let error = error {
print(error)
} else if let data = data,
let dataDictionary = try! JSONSerialization.jsonObject(with: data, options: []) as? NSDictionary {
print("API Data:")
print(dataDictionary)
}
})
task.resume()
Note: This is not the actual API I will be calling
Ideally, for software solutions like financials you mentioned, the server must have support for some sort of Long Polling / websockets mechanism where once connection is established server feeds the client with new values whenever there are updates (refer : https://stackoverflow.com/a/12855533/1436617)
If server does not support : (Not the ideal solution) :
You can actually use recursion in this. On response (both success & failure) of the request again call the same function. That way you can continuously keep polling.
Remember to keep request timer short (5 or 10 seconds instead of 60 seconds) so that if there happens to be an network issue you can quickly make the next call.
I am using the Alamofire Swift library
Alamofire.request
(RestApiManager.sharedInstance.baseURL+"login?language="+lang,
method: .post,
parameters: requestDictionary,
encoding: URLEncoding.httpBody,
headers: headers
).responseObject(keyPath: "") { (response: DataResponse<User>) in
let user = response.result.value
print(user?.status)
print(user?.message)
}
So simply, I want to put a timeout of 60 seconds on every call I make.And i like to give a message connection timeout after 60 seconds. I also want to know, if there exists an internet connection or not. If it doesnt exist, I like to avoid calling alamofire.
Here's the Swift 3.0 / Alamofire 4.0 code to get an alamofireManager that has a 60 second timeout.
You need create a global variable for the request manager:
var alamoFireManager = Alamofire.Manager.sharedInstance
And after configure the custom parameters:
let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
configuration.timeoutIntervalForRequest = 60 // seconds
configuration.timeoutIntervalForResource = 60
self.alamoFireManager = Alamofire.Manager(configuration: configuration)
I set my cache as below
var cacheSizeMemory = 20 * 1024 * 1024
var cacheSizeDisk = 100 * 1024 * 1024
var sharedCache = NSURLCache(memoryCapacity: cacheSizeMemory, diskCapacity: cacheSizeDisk, diskPath: "SOME_PATH")
NSURLCache.setSharedURLCache(sharedCache)
Create request with cache policy
var request = NSMutableURLRequest(URL: NSURL(string: "\(baseUrl!)\(path)")!, cachePolicy: .ReturnCacheDataElseLoad, timeoutInterval: timeout)
Make a request and get a response with following Cache-Control private, max-age=60
Then try to check the cache
var cachedResponse = NSURLCache.sharedURLCache().cachedResponseForRequest(urlRequest)
value is nil
Any thoughts?
I was able to manually cache pages by writing them to the sharedURLCache like this:
Alamofire.request(req)
.response {(request, res, data, error) in
let cachedURLResponse = NSCachedURLResponse(response: res!, data: (data as NSData), userInfo: nil, storagePolicy: .Allowed)
NSURLCache.sharedURLCache().storeCachedResponse(cachedURLResponse, forRequest: request)
}
NSURLCache seems to respect the headers sent by the server, even if you configure the opposite everywhere else in your code.
The Wikipedia API, for example, sends
Cache-control: private, must-revalidate, max-age=0
Which translates to: Must revalidate after 0 seconds.
So NSURLCache says: “OK, I won’t cache anything.”
But by manually saving the response to the cache, it works. At least on iOS 8.2.
Almost lost my mind on this one. :)
I ended up manually adding Cache-Control as private in the header of my request and it now works. Don't even need to manually check the cache, Alamofire does it for you
let cachePolicy: NSURLRequestCachePolicy = isReachable() ? .ReloadIgnoringLocalCacheData : .ReturnCacheDataElseLoad
var request = NSMutableURLRequest(URL: NSURL(string: "\(baseUrl!)\(path)")!, cachePolicy: cachePolicy, timeoutInterval: timeout)
request.addValue("private", forHTTPHeaderField: "Cache-Control")
var alamoRequest = Manager.sharedInstance.request(urlRequest)
I found that URLCache does not save responses bigger than 5% (1/20) of capacity.
Default cache has memoryCapacity = 512000, it does not save to memory responses greater than 25600.
As a solution extend capacity
[Swift solution for resolving expiration of NSURLcache]
I think that main problem here is this: ReturnCacheDataElseLoad.
#arayax gave you the answer that will fix that probably, but my solution would be something like this:
Since I'm using Alamofire for Network requests I've set my configuration:
configuration.requestCachePolicy = .ReturnCacheDataElseLoad
And when I make request I do check internet connectivity, if it is true, then clear NSURLCache, so it will force Alamofire to make request on server and not from cache:
if Reachability.isConnectedToNetwork() == true {
ConfigService.cache.removeAllCachedResponses()
}
ConfigService.manager?.request(.GET, ...
I hope this will help, maybe for other type of problems with NSURLCache :)
For me it was Pragma →no-cache after removing this everything worked.
This is how I got the cache to work with Alamofire 4 and swift 3 (Semi full function for reference):
func getTheList(courseId : String )-> Void{
appConstants.sharedInstance.startLoading()
let TheURL = DEFAULT_APP_URL + "api/getMyList?Id="+ID
let urlString = NSURL(string: TheURL)
var mutableURLRequest = URLRequest(url: urlString! as URL)
mutableURLRequest.httpMethod = "GET"
mutableURLRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
mutableURLRequest.cachePolicy = NSURLRequest.CachePolicy.returnCacheDataElseLoad
Alamofire.request(mutableURLRequest)
.responseJSON
{.......