0

While using NSURLSession to download files and display them in UICollectionView I found a problem where cells do not update correctly from NSOperationQueue block. Download part and file store works correctly every time. But update cell progress or images works only on initial load of controller. If I navigate to root and then again to my Collection controller download works but cells no longer update. I found this interesting discussion but it did not help in my case.

More details, the controller that starts URL session and handles tasks gets loaded from storyboard segue. I noticed app is creating new controller instance every time. On 2nd navigation visit cells do not show progress or update but task/files are download correctly. It seem that my download tasks are getting copy of cells from some other controller instance. But it does not make sense from what I see in debugger, delegates are working correctly, task completes with success.

Here is code method that fail to update cells on 2nd visit to controller:

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

    if (totalBytesExpectedToWrite == NSURLSessionTransferSizeUnknown) {
        NSLog(@"Unknown transfer size");
    }
    else{

    // Locate the FileDownloadInfo object in array based on my unique key in URL.
     int index = [self getFileDownloadInfoIndexWithTaskURL:downloadTask.originalRequest.URL.lastPathComponent];
        // Get singleton download object list from app delegate
        NSMutableArray *globalFileDownloadData = [self getGlobalDownloadFileList];
        FileDownloadInfo *fdi = [globalFileDownloadData objectAtIndex:index];
        // Get the progress view of the appropriate cell and update its progress.
        NSArray *arr = [self.fileDispCollection visibleCells];
        for(FileItemCell* cell in arr){
                if ([fdi.contentId isEqualToString:cell.testLbl.text]){

                    [[NSOperationQueue mainQueue] addOperationWithBlock:^{

                     // This code works when app start initial visit to controller
                     // but does not work on2nd 3rd or other revisit
                     // even cells found correctly, files also loaded saved
                     // the progress does not show and no update

                        cell.downloadProgress.hidden = NO;
                        cell.downloadProgress.progress = fdi.downloadProgress;
                    }];   
                }
            }
    }
}

I initialize my singleton session using this method:

- (NSURLSession *)backgroundSession {
     //disptach_once ensure that multiple background sessions are not 
     //created in this instance of the application. 

    static NSURLSession *session = nil;
    static dispatch_once_t onceToken;

    NSArray *URLs = [[NSFileManager defaultManager]     URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask];
    self.docDirectoryURL = [URLs objectAtIndex:0];
    dispatch_once(&onceToken, ^{

    NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"com.Transport.demo"];
    sessionConfiguration.HTTPMaximumConnectionsPerHost = 3;
    sessionConfiguration.discretionary = NO;
    session = [NSURLSession sessionWithConfiguration:sessionConfiguration
                                                 delegate:self
                                            delegateQueue:nil];
    });
    return session;
}

What can cause a 2nd copy of cells or simply collection cell not to respond to calls or data reload on 2nd navigation round? Hope somebody have a solution for this problem.

Pedram
  • 6,256
  • 10
  • 65
  • 87
takumi3t9
  • 21
  • 1

2 Answers2

1

try to put you update UI code in the main thread like this:

dispatch_async(dispatch_get_main_queue(), ^{
            //your update UI code
        });
Trung Phan
  • 923
  • 10
  • 18
  • I did try this but result was same – takumi3t9 Dec 30 '15 at 05:29
  • dispatch_async(dispatch_get_main_queue(), ^{ fdi.downloadProgress = (double)totalBytesWritten / (double)totalBytesExpectedToWrite; cell.downloadProgress.hidden = NO; cell.downloadProgress.progress = fdi.downloadProgress; NSLog(@"## Update Cell Progress with ID: %@ content: %@", cell.testLbl.text, fdi.contentId); }); – takumi3t9 Dec 30 '15 at 05:30
  • In my previous project, I had the same problem with you, some time it update, some time no, so i custom one by using UIView and update frame width. – Trung Phan Dec 30 '15 at 06:07
1

The answer turned out in my question. The storyboard segue was creating new controller that was creator and handler for URLSession download tasks. Session was singleton that kept initial controller stack and delegate. So new controller instance will start downloads but all responses will go to old controller instance.

Fix was simple not use performSegueWithIdentifier, instead create single controller instance, in this case is actually better solution.

if (!self.library){
        UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle: nil];
        self.library = [storyboard instantiateViewControllerWithIdentifier:@"libraryScene"];
    }
    self.library.model = self.selectNode;
    [self.navigationController pushViewController:self.library animated:YES];
takumi3t9
  • 21
  • 1