NSURLDomainErrorDomain error -999 when app terminate with NSURLSession - ios

I have big trouble with NSURLSession when i'll terminate the App.
I have downloaded the apple sample:
https://developer.apple.com/library/ios/samplecode/SimpleBackgroundTransfer/Introduction/Intro.html
on Apple reference.
When i start download the file download correctly.
When i enter in background the download continues to.
When i terminate the application and i restart the app the application enter in:
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
And i catch this error:
The operation couldn't be completed. (NSURLErrorDomain error -999.)
It seems that i cannot restore download when app has been terminated. It's correct?For proceed with download i must leave application active in background?
Thank you
Andrea

A couple of observations:
Error -999 is kCFURLErrorCancelled.
If you are using NSURLSessionDownloadTask, you can download those in the background using background session configuration, e.g.
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:kBackgroundIdentifier];
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
If not using background session (e.g. you have to use data task, for example), you can use beginBackgroundTaskWithExpirationHandler to request a little time for the app the finish requests in the background before the app terminates.
Note, when using background sessions, your app delegate must respond to handleEventsForBackgroundURLSession, capturing the completion handler that it will call when appropriate (e.g., generally in URLSessionDidFinishEventsForBackgroundURLSession).
How did you "terminate the app"? If you manually kill it (by double tapping on home button, holding down on icon for running app, and then hitting the little red "x"), that will not only terminate the app, but it will stop background sessions, too. Alternatively, if the app crashes or if it is simply jettisoned because foreground apps needed more memory, the background session will continue.
Personally, whenever I want to test background operation after app terminates, I have code in my app to crash (deference nil pointer, like Apple did in their WWDC video introduction to NSURLSession). Clearly you'd never do that in a production app, but it's hard to simulate the app being jettisoned due to memory constraints, so deliberately crashing is a fine proxy for that scenario.

i insert this new lines of code:
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
BLog();
NSInteger errorReasonNum = [[error.userInfo objectForKey:#"NSURLErrorBackgroundTaskCancelledReasonKey"] integerValue];
if([error.userInfo objectForKey:#"NSURLErrorBackgroundTaskCancelledReasonKey"] &&
(errorReasonNum == NSURLErrorCancelledReasonUserForceQuitApplication ||
errorReasonNum == NSURLErrorCancelledReasonBackgroundUpdatesDisabled))
{
NSData *resumeData = error.userInfo[NSURLSessionDownloadTaskResumeData];
if (resumeData) {
// resume
NSURL *downloadURL = [NSURL URLWithString:DownloadURLString];
NSURLRequest *request = [NSURLRequest requestWithURL:downloadURL];
if (!self.downloadTask) {
self.downloadTask = [self.session downloadTaskWithRequest:request];
}
[self.downloadTask resume];
if (!_session){
[[_session downloadTaskWithResumeData:resumeData]resume];
}
}
}
}
It catch NSURLErrorCancelledReasonUserForceQuitApplication but when the application try to [[_session downloadTaskWithResumeData:resumeData]resume]
reenter again in:
(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
and give me again -999 error.

I use this configuration
- (NSURLSession *)backgroundSession
{
/*
Using disptach_once here ensures that multiple background sessions with the same identifier are not created in this instance of the application. If you want to support multiple background sessions within a single process, you should create each session with its own identifier.
*/
static NSURLSession *session = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration backgroundSessionConfiguration:#"com.example.apple-samplecode.SimpleBackgroundTransfer.BackgroundSession"];
session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
});
return session;
}
let me explain what i mean with "terminate the app" (in ios8):
double tap on home button
swipe on my open app.
app disappear from open app list
relaunch app.
When i reopen the app i enter into callback with error
The operation couldn't be completed. (NSURLErrorDomain error -999.)
There is something that i can't understand. This behaviour make me crazy! :-(

Related

NSURLSessionDownloadTask not deleting the file when the app is closed by the user and the task was still active

I have a NSURLSession and a NSURLSessionDownloadTask configured for downloading a file in background, if the download task in canceled by the user all the data is deleted and the storage space the file was using is freed, but if the app is closed from the multitasking dock the download task is terminated and gives an error but is not deleting the data and the temporal data for the file is still occupying storage space and is never freed. What do i need to do in order to free the space ?
This is my NSURLSession configuration and error handling:
- (NSURLSession *)backgroundSession {
static NSURLSession *session = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSURLSessionConfiguration *configuration;
if ([[UIDevice currentDevice].systemVersion hasPrefix:#"7"]) configuration = [NSURLSessionConfiguration backgroundSessionConfiguration:#"com.visyon.pr"];
else configuration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:#"com.visyon.pr"];
configuration.sessionSendsLaunchEvents =YES;
session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
});
return session; }
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
if (error == nil) {
NSLog(#"Task: %# completed successfully", task );
} else {
// [self hideActivity];
// [self showAlertBoxErrorDownload];
NSLog(#"Task: %# completed with error: %#, %lu", task, [error localizedDescription], (long)error.code);
} self.downloadTask = nil; }
ok after more than 10 days of try and fail I found the solution, first of all there are two case scenarios when the user close the app and there is an active download in background, please take in to account that for this cases the download task is never intended to be resumed.
scenario 1. when the user close the app but is still active, the - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error is called and the temporal file that was using for the download goes directly to the temp directory of the app, in this case the - (void)applicationWillTerminate:(UIApplication *)application is called but the delegate of the download task is called first. The solution is this case is to implement code to clean the temp directory every time the app is opened or let iOS to clean the temp folder, it is explained here when iOS is going to clean the temp file:
When does iOS clean the local app ./tmp directories?
scenario 2. when the user close the app in background mode the app is terminated and the next time the app is opened the - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error is called and the temporal file that was using for the download is stored in the NSCachesDirectory in the next directory:
var/mobile/Containers/Data/Application/CA21-B6E8-3305A39/Library/Caches/com.apple.nsurlsessiond/Downloads/com.xxx.xxx/CFNetworkDownload_M5o8Su.tmp
The temporal file will be move to the temporal directory of the app the next time there is a new download.
the solution here is to implement code to delete all temporal files from Caches/com.apple.nsurlsessiond/Downloads/com.xxx.xxx/ as soon as the - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error is launched.
Here is the code in order to delete the temporal files from NSCachesDirectory:
NSString *path = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
NSArray *array = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:[path stringByAppendingPathComponent:#"/com.apple.nsurlsessiond/Downloads/com.xxx.xxx/"] error:nil];
for (NSString *string in array) {
[[NSFileManager defaultManager] removeItemAtPath:[path stringByAppendingPathComponent:[NSString stringWithFormat:#"/com.apple.nsurlsessiond/Downloads/com.xxx.xxx/%#", string]] error:nil];
}
But because it only work for this scenario its better to implement code to clean the temporal directory of the app every time is launched or let iOS to clean the temp folder so it will work for both scenarios.
Here is the code on how to clean the temporal directory of the app:
NSString *path = NSTemporaryDirectory();
NSArray *array = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:nil];
for (NSString *string in array) {
[[NSFileManager defaultManager] removeItemAtPath:[path stringByAppendingPathComponent:string] error:nil];
}
First point is if you are configure nsurlsession with background configuration type. Then this type of session till runing if user kill the app.
Second point if you want to clear space then you need to stop that session and manually write code for deleting temporary file from tmp folder.
Change session configuration type.
There's a method in the AppDelegate called - (void)applicationWillTerminate:(UIApplication *)application. You can try either calling [NSURLSessionDownloadTask cancel]; from there; or try setting a flag to indicate to the app there was a download in progress when the app was closed and delete the data the next time the app is opened.

How to download multiple files by NSURLSessionDownloadTask

iOS 8, XCode 6.3.2
I want to download multiple files serially.
In the wake of the Push notification, APP will start BackgroudDownload by NSURLSessionDownloadTask.
After the First BackgroudDownload process has been completed, APP want to start Second process, but Second BackgroudDownload process does not start.
Code is below
// This method is called by Push Notification
- (void)startBackgroundDownload
{
// Session
NSURLSessionConfiguration *configFirst = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:#"com.test.first"];
sessionFirst = [NSURLSession sessionWithConfiguration:configFirst delegate:self delegateQueue:nil];
NSURLSessionConfiguration *configSecond = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:#"com.test.second"];
sessionSecond = [NSURLSession sessionWithConfiguration:configSecond delegate:self delegateQueue:nil];
// Start First Download
NSURLRequest *requestFirst = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://xxxxx/first.zip"]];
NSURLSessionDownloadTask *downloadTaskFirst = [sessionFirst downloadTaskWithRequest:requestFirst];
[downloadTaskFirst resume];
}
// Finish Download
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
{
if (session == sessionFirst) {
NSURLRequest *requestSecond = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://xxxxx/second.zip"
NSURLSessionDownloadTask *downloadTaskSecond = [sessionSecond downloadTaskWithRequest:requestSecond];
[downloadTaskSecond resume];
} else if (session == sessionSecond) {
NSLog(#"all finish");
}
}
The First is successful, and the Second is fail (not start).
I want advice to pursue the cause.
Thank you for any help you can provide.
downloading task is divide in perfect part like as follow.
First make one array of zip files which you want to download.
Initialise session object
Write one method which can get URL and "startDownloading"
In delegate method (successful download) called unzip that file. remove first object of zip array and again called "startDownloading" method and its call until your array count is greater than zero
I hope you will understand what I want to explain here.

NSURLSessionUploadTask "finishes" but no network traffic

I have an application that uploads several pictures held in an array of TSPhoto objects.
When I start the upload, the delegate method eventually fires to say that it's done, but the app never hits the server and Instruments is showing no network traffic:
_session = [self backgroundSession];
for(TSPhoto *photo in _picsetPhotos) {
NSURL *uploadURL = [NSURL URLWithString:[NSString stringWithFormat:#"%#upload", #"https://example.com/"]];
NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:uploadURL];
[req setHTTPMethod:#"POST"];
NSLog(#"req dump: %#", req);
// Add it to the queue
NSURLSessionUploadTask *uploadTask = [_session uploadTaskWithRequest:req fromFile:[NSURL fileURLWithPath:photo.fullImagePath]];
// "Start" it
NSLog(#"Enqueueing %#", uploadTask);
[uploadTask resume];
NSLog(#"Post-resume");
}
-backgroundSession:
-(NSURLSession *)backgroundSession {
static NSURLSession *session = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:#"TSBackgroundUploader"];
configuration.HTTPMaximumConnectionsPerHost = 1;
session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
});
return session;
}
I have implemented all of the appropriate delegate methods:
-(void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session {
NSLog(#"Finished all uploads!");
[[[UIAlertView alloc] initWithTitle:#"Upload Completed" message:#"Your album has been created." delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil, nil] show];
}
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesSent totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend {
dispatch_async(dispatch_get_main_queue(), ^{
[_uploadProgress setProgress:
(double)totalBytesSent /
(double)totalBytesExpectedToSend animated:YES];
});
}
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
dispatch_async(dispatch_get_main_queue(), ^{
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
[_uploadProgress setProgress:0.5];
// Did we succeed?
if(!error) {
NSLog(#"Upload done");
} else {
NSLog(#"%#", error.description);
}
});
The progress bar also acts really wonky during all of this, rising and falling until eventually reaching 100.
Any clue what might be going on?
edit:
Here's the log after I added some more NSLog statements. The tasks call the delegate in the reverse order in which they were started:
2015-05-04 09:55:42.492 TS[348:95052] Starting background upload
2015-05-04 09:55:42.493 TS[348:95052] req dump: <NSMutableURLRequest: 0x1740138b0> { URL: https://example.com/upload }
2015-05-04 09:55:42.512 TS[348:95052] Enqueueing <__NSCFBackgroundUploadTask: 0x155d804c0>{ taskIdentifier: 3 }
2015-05-04 09:55:42.513 TS[348:95052] Post-resume
2015-05-04 09:55:42.513 TS[348:95052] req dump: <NSMutableURLRequest: 0x17400de00> { URL: https://example.com/upload }
2015-05-04 09:55:42.524 TS[348:95052] Enqueueing <__NSCFBackgroundUploadTask: 0x155e68db0>{ taskIdentifier: 4 }
2015-05-04 09:55:42.525 TS[348:95052] Post-resume
2015-05-04 09:56:01.726 TS[348:95052] ID: 4
2015-05-04 09:56:01.726 TS[348:95052] Upload done
2015-05-04 09:56:02.920 TS[348:95052] ID: 3
2015-05-04 09:56:02.920 TS[348:95052] Upload done
You don't see any network activity because the background session transfers data on a separate daemon that is managed by the system.
This is an excerpt from Apple Documentation:
"Once configured, your NSURLSession object seamlessly hands off upload and download tasks to the system at appropriate times. If tasks finish while your app is still running (either in the foreground or the background), the session object notifies its delegate in the usual way. If tasks have not yet finished and the system terminates your app, the system automatically continues managing the tasks in the background. If the user terminates your app, the system cancels any pending tasks."
You can read more here:
https://developer.apple.com/library/content/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html
Part of me feels really foolish and part of me is really confused.
It turns out that data was being sent. I was working with an incomplete upload endpoint, and when I finished implementing the endpoint, the pictures went through fine!
But for the entire transaction - uploading 10MB worth of pictures - the only network traffic that's showing in the debugger is a few KB for a smaller request I'm making before starting the tasks:
I guess I'll just file this one under "weird shit that Xcode does" and move on.

NSURLSession download task failing after it already succeeded

I am experiencing a strange issue from time to with my NSURLSessionDownloadTasks (using a background download configuration).
It is always related to errors with NSURLDomain code NSURLErrorBackgroundSessionWasDisconnected (-997). The error itself usually seems to be coming from the app generically crashing or being forcefully closed during development from Xcode.
The relevant code boils down to
- (void)download:(NSURLRequest *)request
{
NSURLSessionDownloadTask *downloadTask = [self.urlSession downloadTaskWithRequest:request];
[downloadTask resume];
}
- (void) URLSession:(NSURLSession *)session
downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)tempLocation
{
NSLog(#"task %# didFinishDownloadingToURL with status code %#", downloadTask, #([downloadTask.response statusCode]));
}
- (void) URLSession:(NSURLSession *)session
task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error
{
NSLog(#"task %# didCompleteWithError %#", task, error);
}
The problem in these cases is, that the same NSURLSessionDownloadTask gets two (instead of only one expected) call in -[NSURLSessionTaskDelegate URLSession:task:didCompleteWithError:]. Once without an error (which aligns to a call with a 200 OK response code to -[NSURLSessionDownloadDelegate URLSession:downloadTask:didFinishDownloadingToURL:]) and then another time, usually a couple seconds later with an error (-997). Both times it's exactly the same memory address for the task being passed into these delegate methods.
Has anybody else experienced something similar? I am not expecting that second callback after I was already told that my task succeeded. Is there any obvious reason why the NSURLSession may still hold on to a task it reportedly finished already but then all of a sudden thinks it should inform me that it's lost connectivity to it background transfer service?
FWIW, I had a similar issue because I was updating the UI from the NSURLSession delegate methods, which run in background thread.
So, the solution for me was to move the UI-related code to run on the main thread as below:
dispatch_async(dispatch_get_main_queue(), ^{
//code updating the UI.
});

NSURLSessionTask never calls back after timeout when using background configuration

I am using NSURLSessionDownloadTask with background sessions to achieve all my REST requests. This way I can use the same code without have to think about my application being in background or in foreground.
My back-end has been dead for a while, and I have taken that opportunity to test how does NSURLSession behave with timeouts.
To my utter surprise, none of my NSURLSessionTaskDelegate callbacks ever gets called. Whatever timeout I set on the NSURLRequest or on the NSURLSessionConfiguration, I never get any callback from iOS telling me that the request did finish with timeout.
That is, when I start a NSURLSessionDownloadTask on a background session. Same behavior happens the application is in background or foreground.
Sample code:
- (void)launchDownloadTaskOnBackgroundSession {
NSString *sessionIdentifier = #"com.mydomain.myapp.mySessionIdentifier";
NSURLSessionConfiguration *backgroundSessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfiguration:sessionIdentifier];
backgroundSessionConfiguration.requestCachePolicy = NSURLRequestReloadIgnoringCacheData;
backgroundSessionConfiguration.timeoutIntervalForRequest = 40;
backgroundSessionConfiguration.timeoutIntervalForResource = 65;
NSURLSession *backgroundSession = [NSURLSession sessionWithConfiguration:backgroundSessionConfiguration delegate:self delegateQueue:[NSOperationQueue mainQueue]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:#"http://www.timeout.com/"]];
request.timeoutInterval = 30;
NSURLSessionDownloadTask *task = [backgroundSession downloadTaskWithRequest:request];
[task resume];
}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
NSLog(#"URLSession:task:didCompleteWithError: id=%d, error=%#", task.taskIdentifier, error);
}
However, when I use the default session, then I do get an error callback after 30seconds (the timeout that I set at request level).
Sample code:
- (void)launchDownloadTaskOnDefaultSession {
NSURLSessionConfiguration *defaultSessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
defaultSessionConfiguration.requestCachePolicy = NSURLRequestReloadIgnoringCacheData;
defaultSessionConfiguration.timeoutIntervalForRequest = 40;
defaultSessionConfiguration.timeoutIntervalForResource = 65;
NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration:defaultSessionConfiguration delegate:self delegateQueue:[NSOperationQueue mainQueue]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:#"http://www.timeout.com/"]];
request.timeoutInterval = 30;
NSURLSessionDownloadTask *task = [defaultSession downloadTaskWithRequest:request];
[task resume];
}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
NSLog(#"URLSession:task:didCompleteWithError: id=%d, error=%#", task.taskIdentifier, error);
}
I cannot seem to find in the documentation anything that suggests that the timeout should behave differently when using background sessions.
Has anyone bumped into that issue as well?
Is that a bug or a feature?
I am considering creating a bug report, but I usually get feedback much faster on SO (a few minutes) than on the bug reporter (six months).
Regards,
Since iOS8, the NSUrlSession in background mode does not call this delegate method if the server does not respond.
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
The download/upload remains idle indefinitely.
This delegate is called on iOS7 with an error when the server does not respond.
In general, an NSURLSession background session does not fail a task if
something goes wrong on the wire. Rather, it continues looking for a
good time to run the request and retries at that time. This continues
until the resource timeout expires (that is, the value of the
timeoutIntervalForResource property in the NSURLSessionConfiguration
object you use to create the session). The current default for that
value is one week!
Quoted information taken from this Source
In other words, the behaviour of failing for a timeout in iOS7 was incorrect. In the context of a background session, it is more interesting to not fail immediately because of network problems. So since iOS8, NSURLSession task continues even if it encounters timeouts and network loss. It continues however until timeoutIntervalForResource is reached.
So basically timeoutIntervalForRequest won't work in Background session but timeoutIntervalForResource will.
Timeout for DownloadTask is thrown by NSURLSessionTaskDelegate not NSURLSessionDownloadDelegate
To trigger a timeout(-1001) during a downloadTask:
Wait till download starts.
percentage chunks of data downloading will trigger:
URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite:
Then PAUSE the whole app in XCode debugger.
Wait 30secs.
Unpause the app using XCode debugger buttons
The http connection from server should time out and trigger:
-1001 "The request timed out."
#pragma mark -
#pragma mark NSURLSessionTaskDelegate - timeouts caught here not in DownloadTask delegates
#pragma mark -
- (void)URLSession:(NSURLSession *)session
task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error
{
if(error){
ErrorLog(#"ERROR: [%s] error:%#", __PRETTY_FUNCTION__,error);
//-----------------------------------------------------------------------------------
//-1001 "The request timed out."
// ERROR: [-[SNWebServicesManager URLSession:task:didCompleteWithError:]] error:Error Domain=NSURLErrorDomain Code=-1001 "The request timed out." UserInfo={NSUnderlyingError=0x1247c42e0 {Error Domain=kCFErrorDomainCFNetwork Code=-1001 "(null)" UserInfo={_kCFStreamErrorCodeKey=-2102, _kCFStreamErrorDomainKey=4}}, NSErrorFailingURLStringKey=https://directory.clarksons.com/api/1/dataexport/ios/?lastUpdatedDate=01012014000000, NSErrorFailingURLKey=https://directory.clarksons.com/api/1/dataexport/ios/?lastUpdatedDate=01012014000000, _kCFStreamErrorDomainKey=4, _kCFStreamErrorCodeKey=-2102, NSLocalizedDescription=The request timed out.}
//-----------------------------------------------------------------------------------
}else{
NSLog(#"%s SESSION ENDED NO ERROR - other delegate methods should also be called so they will reset flags etc", __PRETTY_FUNCTION__);
}
}
There is one method in UIApplicationDelegate,which will let you know about background process.
-(void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler
If there are more than one session ,you can identify your session by
if ([identifier isEqualToString:#"com.mydomain.myapp.mySessionIdentifier"])
One more method is used to periodically notify about the progress .Here you can check the state of NSURLSession
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
NSURLSessionTaskStateRunning = 0,
NSURLSessionTaskStateSuspended = 1,
NSURLSessionTaskStateCanceling = 2,
NSURLSessionTaskStateCompleted = 3,
Like you, the app I'm working on always uses a background session. One thing I noticed is that the timeout works properly if it's interrupting a working connection, i.e., the transfer started successfully. However, if I start a download task for a URL that doesn't exist, it wouldn't time out.
Given that you said your backend had been dead for awhile, this sounds a lot like what you were seeing.
It's pretty easy to reproduce. Just set a timeout for like 5 seconds. With a valid URL you'll get some progress updates and then see it timeout. Even with a background session. With an invalid URL it just goes quiet as soon as you call resume.
I have come up to the exact same problem. One solution that i have found is to use two sessions, one for foreground downloads using the default configuration and one for background downloads with background configuration. When changing to the background/foreground generate resume data and pass it from one to the other. But i am wondering if you have found another solution.

Resources