3

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***********");    
}
Julian
  • 9,299
  • 5
  • 48
  • 65
ehassan2014
  • 99
  • 1
  • 5
  • I've noticed similar behaviour. In particular, if I break before the task creation and step over it, I get nil. If I break after the task creation I get a task returned. This is in the simulator. – Felix Jan 12 '14 at 23:57
  • I've run into same problem(tested it on device), same symptoms. When you run ``downloadTaskWithRequest:`` in ``application:performFetchWithCompletionHandler:``, you get nil. – desudesudesu Jan 28 '14 at 10:42
  • I've also seen this happen on a real device. (iOS 7.0.3.) – TJez Feb 07 '14 at 06:06
  • I'm also seeing that when coming into the foreground, sometimes it fails to call "didCompleteWithError" or "didFinishDownloadingToURL" (from NSURLSessionTaskDelegate) for the tasks created just after coming back into the foreground. Hope this helps someone. – TJez Feb 07 '14 at 06:28

1 Answers1

0

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".

Clay Bridges
  • 11,602
  • 10
  • 68
  • 118