1

I have a problem with some GUI components in my iOS app when using NSURLSession delegates.

I have a UITableViewController which show different map areas to a user. The user can pick one of these areas and I will push a new UIViewController showing some details about this area. Inside the UIViewController the user can click a button to download this map area.

I use NSURLSession to download the map. I have my own method for setting up the session.

- (NSURLSession *)backgroundSession {
    static NSURLSession *session = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{

        NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"com.example.app"];


        sessionConfiguration.HTTPMaximumConnectionsPerHost = 2;
        session = [NSURLSession sessionWithConfiguration:sessionConfiguration
                                            delegate:self
                                       delegateQueue:nil];
    });

    return session;
}

And I start the download by

self.downloadTask = [self.session downloadTaskWithURL:[NSURL URLWithString:hikingMap.downloadSource]];
[downloadTask resume];

This works very fine on the first area I open from the UITableViewController.

Example:

1. Go to area A
2. Start downloading area A

However, my problem arises when I look at some areas first and then later go to another area and try to download this area.

Example:

1. Go to area A
2. Go back to UITableViewController
3. Go to area B
4. Start downloading area B

The actual download runs just fine. However, I make some changes to the GUI once the download starts. I hide some labels and show some UIProgressViews.

I do those changes in the delegate method for the download progress:

-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{

    dispatch_async(dispatch_get_main_queue(), ^{
         self.label.hidden = YES;
         self.progressView.hidden = NO;
    });

}

Those hidden changes is not reflected in my GUI. Basically all changes to the GUI I do outside of the delegate methods works just fine, but none of the changes I do inside the delegate methods works.

I do not understand how I can solve this problem. So any help would be great! Tell me if I need to add more code for you to understand what is going on.

UPDATE

I have now confirmed that the delegate method uses an old reference to the UIlabel. I test by changing the label text when opening area A and when I then go to area B and do the download I see that the label text in the delegate methods is the same as it was in area A.

Espen
  • 110
  • 8
  • are you sure, thet this method is called? – mityaika07 Nov 05 '14 at 13:55
  • Yes it runs. I checked it in the debugger. – Espen Nov 05 '14 at 13:58
  • Why are you using `nil` for the delegateQueue if you're going to dispatch to the main queue anyway? Why aren't you using `dispatch_get_main_queue()` directly in `sessionWithConfiguration:delegate:delegateQueue:`? – Guillaume Algis Nov 05 '14 at 14:01
  • Because I do not know what I am doing @guillaume-algis :-) However, I tried to set the `delegateQueue` to `dispatch_get_main_queue()` but that just makes the app crash. – Espen Nov 05 '14 at 14:27
  • Sorry, use `[NSOperationQueue mainQueue]` instead of `dispatch_get_main_queue()`. – Guillaume Algis Nov 05 '14 at 14:29
  • OK, that works without crashing the app, but it does not solve the main GUI problem. @guillaume-algis – Espen Nov 05 '14 at 14:46
  • Yes, I'm not surprised, this does the same thing than what you did, it's just "cleaner" :). You are sure that the method is called, but did you check that `self.label` and `self.progressView` are not `nil`? – Guillaume Algis Nov 05 '14 at 14:52
  • Just to make things clear. How much times do you call the `-(NSURLSession *)backgroundSession` method? – Daniyar Nov 05 '14 at 15:01
  • They are not nil @guillaume-algis – Espen Nov 05 '14 at 15:17

2 Answers2

0

Your -(NSURLSession *)backgroundSession method is not safe. The second time you call it, session variable set to nil and doesn't initialize properly. Try this fix

static NSURLSession *_sharedSession;
- (NSURLSession *)backgroundSession
{
  if (!_sharedSession)
  {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"com.example.app"];
        sessionConfiguration.HTTPMaximumConnectionsPerHost = 2;
        sharedSession = [NSURLSession sessionWithConfiguration:sessionConfiguration
                                            delegate:self
                                       delegateQueue:nil];
    });
  }
  return _sharedSession;
}
Daniyar
  • 2,975
  • 2
  • 26
  • 39
  • OK, I need to run, but I will check this one out in a few hours. – Espen Nov 05 '14 at 15:17
  • I understand the reason for this code and I will keep it. However, I have tested it out and unfortunately it did not change anything. @astoria – Espen Nov 05 '14 at 18:21
0

I had same problem while uploading.

To overcome it, you have to invalidate and cancel your shared session (NSURLSession). In Swift, you can do it as follows:

session.invalidateAndCancel()
Vishal
  • 2,161
  • 14
  • 25