download task is null for the first request when when in backgroundfetch IOS

1.2k Views Asked by At

I was wondering if you have seen this or might have some ideas as to why I see the following behavior in my code: I have an NSURLsession with background config. I initiate periodic download task when the program runs in the Foreground, and everything works. WhenI simulate backgroundfetch (in xcode), my task gets a null value (eventhough the request and the session are not null). of course in this case, my session delegate never gets fired to do completionhandler. if I simulate subsequent background fetches, they all work afterward. at this point, if I bring the app to the foreground in the simulator, and I simulate another backgroundfetch, the symptoms star all over. I am using this code in my appdelegate class.

your help is greatly appreciated.

- (NSURLSession *)FlickrSession
{

if(!_FlickrSession)
{
    NSLog(@"setting new FlickrSession");
    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration   backgroundSessionConfiguration:FLICKR_SESSION];
    configuration.allowsCellularAccess = NO;

    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _FlickrSession = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
        _FlickrSession.sessionDescription = FLICKR_SESSION;
        NSLog(@" new self is  %@", _FlickrSession);
        NSLog(@"queue in session   %@", dispatch_get_current_queue());

    });
}
return _FlickrSession;

}

-(void) startFlickrFetch
{
// initialize session config and the background session

[self.FlickrSession getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks)
{
    if(![downloadTasks count])
    {
        NSLog(@"new downloadtask session %@", self.FlickrSession.sessionDescription);


        NSURLRequest *request = [NSURLRequest requestWithURL:[FlickrFetcher URLforRecentGeoreferencedPhotos]];
       // NSURLSessionDownloadTask *task = [self.FlickrSession downloadTaskWithURL:[FlickrFetcher URLforRecentGeoreferencedPhotos]];
        NSURLSessionDownloadTask *task = [self.FlickrSession downloadTaskWithRequest:request];
        task.taskDescription = FLICKR_DOWNLOAD_TASK;
        NSLog(@"new request %@", request);
        NSLog(@"new downloadtask %@", task);
        [task resume];
        //task?[task resume]:[self fireBackgroungFetchCompletionHandler];;
            //[self fireBackgroungFetchCompletionHandler];
        NSLog(@"queue in task  %@", dispatch_get_current_queue());
    }
    else
    {
        NSLog(@"resuming old downloadtask %d", [downloadTasks count]);
        for(NSURLSessionDownloadTask *task in dataTasks) [task resume];

    }

}];
NSLog(@"queue outside the block   %@", dispatch_get_current_queue());

}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions
{
    // Override point for customization after application launch.
    // open the file, if there is no managedContext. this is the case wjere the application  was launched directly by user
    // it did not come from the bckground state;


    //need to enable background fetch
    [[UIApplication sharedApplication] setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];


//[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(documentChangedState) name:UIDocumentStateChangedNotification object: self.document];
    NSLog(@"in application didfinishlaunching");

    [self openDatabaseFile];
    [self startFlickrFetch];



    return YES;
}

-(void) application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{

    self.backgroundFetchCompletionHandler = completionHandler;
    if(self.document.documentState == UIDocumentStateNormal)
    {
       //[self openDatabaseFile];

        NSLog(@"in performFetchWithCompletionHandler");

        [self startFlickrFetch];
    }

}

- (void) application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler
{


    self.completionhandler = completionHandler;
    NSLog(@"handle event for backgroundURLsession***********");    
}
1

There are 1 best solutions below

0
On

This could have something to do with a strange interaction of the background fetch and a background session, in which case I have no advice.

However, in the background, iOS doesn't know to wait for async calls, e.g. getTasksWithCompletionHandler. You can solve this by wrapping those calls with a UIBackgroundTaskIdentifier†-based [UIApplication] begin/end task (in this case, with the "end (app) task" inside the "get (session) tasks completion handler" block).

But if all you need is a count, here's what I did, which I think is simpler:

Create an ivar:

NSMutableSet *activeTaskIDs;

When you create a task, add it to the set:

[activeTaskIDs addObject:@(task.taskIdentifier)];

When the task completes, remove it.

You can get your count from there, no async.

† Confusingly, a different kind of task. I differentiate with the terms "app tasks" vs. "session tasks".