Setting NSURLRequestCachePolicy and NSURLSession - ios

I'm creating an NSURLSession with a sessionConfiguration where I have explicitly set the requestCachePolicy and URLCache.
sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
sessionConfiguration.requestCachePolicy = NSURLRequestReturnCacheDataElseLoad;
sessionConfiguration.URLCache = [NSURLCache sharedURLCache];
A request is created and passed as an argument in NSURLSession dataTaskWithRequest:CompletionHandler: method. The request is constructed like this:
request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:kAENServiceNetworkTimeout];
Problem 1:
Setting up like this, no fsCachedData Folder is created on disk and cached data is not used. If the request is created simply using:
request = [NSMutableURLRequest requestWithURL:url];
The cache is created on disk, and the image is used as expected. Is this a bug in Apple's code?
Problem 2:
In neither of these cases is the URLSession:dataTask:willCacheResponse:completionHandler: delegate method called. Are their situations under which this would be the case?
Update:
I've pushed an example project to Github, https://github.com/mattmorton/cache-testing

Problem 1:
I think my understanding of the NSURLRequestReturnCacheDataElseLoad was incorrect. In this case the response is not cached.
Problem 2:
From Apple header for NSURLSession in the NSURLSessionAsynchronousConvenience category:
data task convenience methods...create tasks that bypass the normal delegate calls for response and data delivery, and provide a simple cancelable asynchronous interface to receiving data.
I am using a convenience method handler, hence why the delegate method is not being called.

Related

iOS: NSURLCache with NSURLSession alongside HTTP headers

NSURLCache is some kind of a dark art magic that is neither documented properly, nor behaves as expected.
I am using AFNetworking's AFHTTPSessionManager to utilise NSURLSession. I am using this mocking service to create custom HTTP responses.
I am setting the NSURLCache with disk capacity and all the cache policies.
Then in the URLSession:task:didCompleteWithError method of NSURLSessionTaskDelegate, I am doing this:
NSURLRequest *request = task.currentRequest;
NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request];
The documentation states about the cachedResponseForRequest:
#result The NSCachedURLResponse stored in the cache with the given
request, or nil if there is no NSCachedURLResponse stored with the
given request.
AFNetworking's FAQ states:
So long as your NSURLRequest objects have the correct cache policy,
and your server response contains a valid Cache-Control header,
responses will be automatically cached for subsequent requests.
After all this my assumption is that the value of the the cachedResponse variable will be nil if the Cache-Control is NOT set properly. However, whatever I have tried to do so far - setting it to 'private', 'no-cache' or whatever - the cachedResponse ALWAYS contains the cached response. How can I verify that the caching mechanism works as expected ? Is there anything that I am missing from the setup ?
I have been doing my tests by firstly making the request online, then switching off the internet on my computer. XCode 7.0 beta iOS 9.0.
Any help is appreciated.

Getting an NSURLRequest for use in UIImageView setImageWithURLRequest:placeholderImage:success:failure:

This question assumes AFNetworking 2.0.
I have an AFHTTPRequestOperationManager, and I have a UIImageView. My URL for the image in question requires authentication and several parameters.
With AFNetworking 1.x I had an AFHTTPClient that I could use to get a NSURLRequest from and then pass that into the UIImageView setImageWithURLRequest:... method. I can't find anything in the AFHTTPRequestOperationManager that returns an NSURLRequest.
Am I just blind?
Have you looked into AFURLSessionManager? Looks like it supports downloading and you set the NSURLRequest yourself so you could set the params and all that:
https://github.com/AFNetworking/AFNetworking#afurlsessionmanager
It looks like there is no way to have the AFHTTPRequestOperationManager make a NSURLRequest for me. However, the requestSerializer will make one so I am using that. The only problem is that the requestSerializer doesn't know about the baseURL, so I have to pull that out of the operation manager first.
NSString* fullPath = [self.HTTPRequestOperationManager.baseURL.absoluteString stringByAppendingString: path];
NSMutableURLRequest* urlRequest = [self.HTTPRequestOperationManager.requestSerializer requestWithMethod: #"GET" URLString: fullPath parameters: parameters error: &error];
I'll have to suggest this as a feature request. I should not have to pull one piece of information out the a RequestOperationManager only to send it to another piece of the same RequestOperationManager.

ASIHTTPRequest addRequestHeader issue

I am using ASIHttpRequest and make use GET method to send header to server. I call method addRequestHeader like this
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request addRequestHeader:#"myHeader" value:#"abc"];
It's not working. But if I use NSMutableURLRequest to add header and request to server, it works.
I don't know anything wrong when calling addRequestHeader methods for ASIHTTPRequest library.
Have anyone seen this issue?
Wow ok so, yeah if this is a new app, please do NOT use ASIHttpRequest. It has long been supplanted by the delightful AFNetworking.
If this is an existing application, you really should work on a migration plan off ASI.
However, in an attempt to actually answer your question - that is the appropriate setup per the documentation, and is how I used to use it. My guess is something is broken under the covers and judging from a basic google request, there are issues with iOS 7 including memory leaks and requests just failing.
You can do it via NSURLRequest
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.abc.com"]];
NSMutableURLRequest *mutableRequest = [request mutableCopy];
[mutableRequest addValue:#"AAA" forHTTPHeaderField:#"Hello-there"];
request = [mutableRequest copy];
NSLog(#"%#", request.allHTTPHeaderFields);
Hope this helps .. :)

NSURLRequest: Always getting NSCachedURLResponse back.

I'm using AfNetworking, I make a call for new data but I keep getting the cached result back. So if I'm in a VC that's shows the data, pop back to the root and change data on my server, I then wait 30sec and when I push back into the VC I'll see the the old data. If I hit the URL in a browser I see the correct data. If I re-run the app I will see the changes to the data.
My response from my server sends back cache control header: Cache-Control:max-age=10, public
From what I can tell is that I always always get a NSCachedURLResponse back and that the cache is not listening to my cache-controll policy.
In my AppDelegate I set my SharedURLCache:
NSURLCache *URLCache = [[NSURLCache alloc] initWithMemoryCapacity:8 * 1024 * 1024 diskCapacity:8 * 1024 * 1024 diskPath:nil];
[NSURLCache setSharedURLCache:URLCache];
How I set the URLRequest:
NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:30.0];
I do nothing else involving NSURLCache.
Any ideas?
BooRanger
The behavior you describe is exactly what I'd expect from the code you've posted. Have you tried using NSURLRequestReloadIgnoringLocalAndRemoteCacheData instead of NSURLRequestUseProtocolCachePolicy? According to this NSURLRequestUseProtocolCachePolicy means:
Specifies that the caching logic defined in the protocol
implementation, if any, is used for a particular URL load request.
This is the default policy for URL load requests.
So if you want it to always load from the server, you should use NSURLRequestReloadIgnoringLocalAndRemoteCacheData which is described as:
Specifies that not only should the local cache data be ignored, but
that proxies and other intermediates should be instructed to disregard
their caches so far as the protocol allows.

How to write data to the web server from iPhone application?

I am looking forward for posting some data and information on the web server through my iPhone application. I am not getting the way to post data to the web server from iPhone sdk.
It depends in what way you want to send data to the web server. If you want to just use the HTTP POST method, there are (at least) two options. You can use a synchronous or an asynchronous NSURLRequest. If you only want to post data and do not need to wait for a response from the server, I strongly recommend the asynchronous one, because it does not block the user interface. I.e. it runs "in the background" and the user can go on using (that is interacting with) your app. Asynchronous requests use delegation to tell the app that a request was sent, cancelled, completed, etc. You can also get the response via delegate methods if needed.
Here is an example for an asynchronous HTTP POST request:
// define your form fields here:
NSString *content = #"field1=42&field2=Hello";
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:#"http://www.example.com/form.php"]];
[urlRequest setHTTPMethod:#"POST"];
[urlRequest setHTTPBody:[content dataUsingEncoding:NSISOLatin1StringEncoding]];
// generates an autoreleased NSURLConnection
[NSURLConnection connectionWithRequest:request delegate:self];
Please refer to the NSURLConnection Class Reference for details on the delegate methods.
You can also send a synchronous request after generating the request:
[NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
If you pass a NSURLResponse ** as returning response, you will find the server's response in the object that pointer points to. Keep in mind that the UI will block while the synchronous request is processed.

Resources