Clear NSURLSession Cache - ios

I'm using NSURLSession to perform an HTTP Post NSMutableURLRequest, using the dataTaskWithRequest:completionHandler: method. When I perform a request for the first time, things take a reasonable amount of time to complete and show some feedback in the completion handler. On the next time that same request is fired, it happens almost instantaneously with very little time in between, which leads me to believe that the system is caching the contents of this data task.
As I don't need to view the returned data, is NSURLSession the best way to do this? It needs to work well with WatchKit, which NSURLSession does, which is why I chose it in the fist place. I would preferably like to find a way to just clear the cache after each request. If need be, I could switch to NSURLConnection, but this would be best. Thanks!

Ephemeral mode will not use any cache.
NSURLSessionConfiguration *ephemeralConfigObject = [NSURLSessionConfiguration ephemeralSessionConfiguration];

Related

NSURLSession set request timeout accurately

We set timeout interval for a request by NSMutableURLRequest timeoutInterval. As Apple's document described, it specifies the limit between packets, not the whole request. When we analyse our requests logs, some timeout request exceeded the seconds we set to timeoutInterval. We need timeout the requests accurately.
By reading document and blogs, the timeoutIntervalForRequest property in NSURLSessionConfiguration is the same as timeoutInterval. But the timeoutIntervalForResource property seems fit our requirement.
However, Mattt says in objc.io that timeoutIntervalForResource "should only really be used for background transfers". Can it be used in normal request? Such as query user info. Is it appropriate in this situation?
Thanks very much.
It can be used, but it rarely makes sense to do so.
The expected user experience from an iOS app is that when the user asks to download or view some web-based resource, the fetch should continue, retrying/resuming as needed, until the user explicitly cancels it.
That said, if you're talking about fetching something that isn't requested by the user, or if you are fetching additional optional data that you can live without, adding a resource timeout is probably fine. I'm not sure why you would bother to cancel it, though. After all, if you've already spent the network bandwidth to download half of the data, it probably makes sense to let it finish, or else that time is wasted.
Instead, it is usually better to time out any UI that is blocked by the fetch, if applicable, but continue fetching the request and cache it. That way, the next time the user does something that would cause a similar fetch to occur, you already have the data.
The only exception I can think of would be fetching video fragments or something similar, where if it takes too long, you need to abort the transfer and switch to a different, lower-quality stream. But in most apps, that should be handled by the HLS support in iOS itself, so you don't have to manage that.

AFHTTPSessionManager convenience methods (GET, POST, PUT, etc) and background transfers

I've built an app around AFNetworking 2.0's AFHTTPSessionManager and its nice HTTP convenience methods. I now need to ensure that all of this networking functionality can run in the background, and I'm rather concerned.
Reading Apple's documentation, I can see that data tasks are not supported for background sessions. After looking briefly at AFHTTPSessionManager's implementation of GET, POST, PUT et al, it seems to use NSURLSessionDataTask across the board.
Is there something I'm missing, or do I have some redesign and rework to do?
In the event that I'm right (and I suspect I am), and that this codepath won't allow me to background uploads and downloads, is there any reason I couldn't wrap AFURLSessionManager's other methods that use non-data tasks in the same way the current HTTP methods wrap "dataTaskWithRequest:completionHandler"? For example for a POST I could perhaps use "uploadTaskWithRequest:fromData:progress:completionHandler"?
I'm asking, since I'm wondering if this is a viable route, why the AFNetworking devs didn't use it, so that AFHTTPSessionManager's convenience methods would allow for background transfers.
AFNetworking allows you to perform background requests (though be careful to not use any of the task-specific completion blocks and make sure you implement the appropriate app delegate methods; see AFNetworking 2.0 and background transfers). You probably also can use requestWithMethod of AFHTTPRequestSerializer to simplify the process of building the request, too (though, IIRC, you cannot use HTTPBody of the request with background upload requests, so you might have to save the body of the request to a file and then issue your background upload request using that file).
But you're absolutely correct that you cannot use the AFHTTPSessionManager methods to initiate NSURLSessionDataTask tasks when using background session. Regarding why they implemented it that way, that's a question better suited for their issues forum.

How do I cancel a download with AFHTTPSessionManager?

My app downloads information using a subclass of AFHTTPSessionManager and GET. The user may opt out of the download and I am trying to figure out how to cancel the download.
I came across this code:
- (void) cancel {
[self.operationQueue cancelAllOperations];
}
But that didn't seem to work, since the download completed.
I then tried:
- (void) cancel {
for (NSURLSessionTask *task in self.tasks) {
[task cancel];
}
}
This did seem to interrupt the download, but I am not sure if this is the proper way to do this. The docs are not very helpful for this (or I haven't found it yet).
So, is the above the correct way to cancel my download? Do I need to do more cleanup?
You certainly do not want to use cancelAllOperations. That is fine with operation-based AFHTTPRequestOperationManager requests, but not the task-based AFHTTPSessionManager requests. Sadly, AFHTTPSessionManager does not use operations. I understand why (wrapping the tasks in operations is surprisingly complicated given the fact that NSURLSessionTask delegates are specified at the session level (!), it's incompatible with background sessions, etc.), but it's too bad, as it significantly diminishes the value of AFHTTPSessionManager, IMHO. Mattt once said that he was going to remedy this, but it's never been released.
Your second approach of canceling the individual tasks is fine. You could also call invalidateSessionCancelingTasks, but you'd presumably have to re-instantiate the session (or the entire AFHTTPSessionManager) when you want to initiate more requests.

iOS - Perform synchronous HTTP request with AFNetworking

I'm currently migrating my app from using ASIHTTPRequest to AFNetworking. I know synchronous requests are to be avoided if possible, but in my app I have just 1 place where I use one. In the app delegate applicationDidEnterBackground() method I need to run a HTTP request to query data to set the application badge number when the app goes to background. When run asynchronously this rarely works because the method just drops out and the application is suspended before the HTTP request completes. With ASIHTTPRequest I used the [request startSynchronous] method and this meant the HTTP request completed 100% every time and the badge was updated correctly. I see with AFNetworking there is no obvious synchronous option, so can anybody suggest a way it can be used synchronously, or an alternative solution?
Have found the way to do this - using one of the AFHTTPRequestOperation derivatives there is the method - setShouldExecuteAsBackgroundTaskWithExpirationHandler: which gives the operation extra time to complete before the OS suspends the app. So my code is :
[operation setShouldExecuteAsBackgroundTaskWithExpirationHandler:nil];
[operation start];
This was just what I needed and has solved my problem.
Jonathan
UPDATE: As Bob has pointed out using this method does not actually perform the operation synchronously, but was the ideal solution in my case in the absence of a synchronous method.

NSNotification-based iOS App

I am currently thinking about the data-model for my iOS App. The app does only receive Information from a server and therefore, the "model" itself generally does all the web-requests, ...
However, these network requests have to be performed in the background - I mean another task, not the iOS background state - and after the request has finished, the information in the Application has to be updated.
Would it make more sense to write a delegate to inform the controller or could I also use NSNotificationCenter? I think an NSNotification-based solution could make the model more universal, e.g. in a desktop application.
And maybe, I should add: the model (since it saves some session Information) is a singleton, so a regular delegate based method would not work...
I don't think that it would be a good idea to use a separate thread to handle the communication. Apart from being complex, it is not necessary since NSURLConnection/NSURLRequest do allow you to handle communication asynchronously, i.e., without blocking.
In detail, you can create an NSURLRequest executing:
NSURLRequest* yourReq = [NSURLRequest requestWithURL:yourURL];
then create an NSURLConnection with:
NSURLConnection* yourConnection = [NSURLConnection connectionWithRequest:yourReq delegate:yourDelegate];
and start it with:
[yourConnection start];
When the data is ready, one of the methods for your delegate (connectionDidFinishLoading:, or connection:didFailWithError:) will be called so that you can update your UI.
All this without blocking.
An even better alternative to using NSURLConnection/NSURLRequest, is using ASIHTTPRequest, which seems to be more resilient as to memory management and also offers a great caching mechanism.
EDIT: if your concern is that being your model a singleton, you cannot have a delegate, let me suggest that you look further into the matter.
Your model may be a singleton and the delegate to your request may have nothing to do with the model, apart from knowing how to access it (which is pretty trivial being the model a singleton).
This is possible by several mechanisms with NSURLConnection, but if you use ASIHTTPRequest, it will become really easy, because each ASIHTTRequest can have its own delegate.
A delegate solution does work and is recommended. It looks something like:
[[DataLayer sharedInstance] fetchDataWithDelegate:self];
That method can spawn a background thread and respond to the delegate on the main thread.

Resources