Search code examples
objective-cmultithreadingnsoperationqueue

Using NSOperationQueue for downloading forms in background


I need to download a number of forms from web service.For that I have used NSOperationQueue like this

operationQueue = [NSOperationQueue new];
    for (int i=0;i<[tempArray count];i++) {
        CheckList * checklist = (CheckList *)[tempArray objectAtIndex:i];

        NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self
                                                                                selector:@selector(downloadChecklistsInBackground:)
                                                                                  object:checklist];
        [operationQueue addOperation:operation];

The idea is , it should get executed without affecting the screen operations. And in the UI there will be separate download button for each of the forms.So if user clicks on any one of them, it should be downloaded immediately and it should be removed from the background process.The code is given below.

-(void)downloadChecklistsInBackground:(CheckList *)checklist
{
    BOOL isDone = NO;
    for (int j=0; j<[selectedArray count]; j++) {
        if([checklist.checklistId isEqualToString:[selectedArray objectAtIndex:j]])
        {
            isDone = YES;

        }
    }
    if(!isDone)
    {
        [backGroundQueueArr addObject:checklist];

        NSString * urlStr = [[BASE_URL stringByAppendingString:DOWNLOAD_CHECKLIST_URL] stringByAppendingFormat:@"%@/%d/%@/%@/%@",[ChecklistSingleton sharedSingleton].userSSO,[checklist.checklistId intValue],checklist.language,checklist.baseFormId,checklist.versionNo];
        NSURL * url = [NSURL URLWithString:urlStr];
        NSLog(@"url is %@",url);

        NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
        NSURLSession *session = [NSURLSession sessionWithConfiguration:config];

        NSMutableURLRequest * request = [[NSMutableURLRequest alloc] initWithURL:url];
        AppDelegate * appDelegateObj = (AppDelegate *)[[UIApplication sharedApplication] delegate];
        [request setValue:[NSString stringWithFormat:@"Bearer %@",appDelegateObj.accessToken ]forHTTPHeaderField:@"Authorization"];
        [request setTimeoutInterval:240.0];
        [request setValue:@"Application/JSON" forHTTPHeaderField:@"Content-Type"];
        NSURLSessionDataTask * downloadTask =[session dataTaskWithRequest:request completionHandler:^(NSData * data, NSURLResponse * response, NSError * error)
                                              {
                                                  NSString * str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
                                                  NSLog(@"response is %@",str);
                                              }];
        [downloadTask resume];

    }


}
-(void)downloadCecklistWithChecklist:(CheckList *)check5
{

    [selectedArray addObject:check5];
    BOOL isDownloaded = NO;
    for (int j=0; j<[backGroundQueueArr count]; j++) {
        CheckList * checklistTobeChecked = [backGroundQueueArr objectAtIndex:j];
        if([checklistTobeChecked.checklistId isEqualToString:check5.checklistId])
        {
            isDownloaded = YES;
        }
    }
    if(!isDownloaded)
    {

    NSString * urlStr = [[BASE_URL stringByAppendingString:DOWNLOAD_CHECKLIST_METADATA_SUBURL] stringByAppendingFormat:@"%@/%d/%@/%@/%@",[ChecklistSingleton sharedSingleton].userSSO,[check5.checklistId intValue],check5.language,check5.baseFormId,check5.versionNo];
    NSURL * url = [NSURL URLWithString:urlStr];
    NSLog(@"url is %@",url);

    NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
    NSURLSession *session = [NSURLSession sessionWithConfiguration:config];

    NSMutableURLRequest * request = [[NSMutableURLRequest alloc] initWithURL:url];
    AppDelegate * appDelegateObj = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    [request setValue:[NSString stringWithFormat:@"Bearer %@",appDelegateObj.accessToken ]forHTTPHeaderField:@"Authorization"];
    [request setTimeoutInterval:240.0];
    [request setValue:@"Application/JSON" forHTTPHeaderField:@"Content-Type"];
    NSURLSessionDataTask * downloadTask =[session dataTaskWithRequest:request completionHandler:^(NSData * data, NSURLResponse * response, NSError * error)
                                          {
                                              NSString * str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
                                              NSLog(@"response is specific %@",str);
                                          }];
    [downloadTask resume];
    }


}

Could you please help me with the correct approach for this.I know that, this piece of code doesn't implement threading properly. Please guide me on this.Thank you very much in advance.


Solution

  • NSURLSession is already wraps the async download operation in this case you don't have to call it from NSInvocationOperation. I would suggest you to :

    1) init your buttons tag with the index of each checklist index

    2) hold NSMutableIndexSet of downloaded check lists

    3) disable the clicked button while its downloading

    4) add the index of downloaded checklist

    5) check if all list were downloaded if yes remove all from tempArray

    6) enable the button

    create a general event for all buttons like:

    -(IBAction)myButtonClickEvent:(id)sender{
    
      // 2 - protects your data from being downloaded twice
      if([indexSet contains:sender.tag])
         return;
      // 3 - disable while downloading
      sender.enabled = NO;
      CheckList * check5 = [tempArray objectAtIndex : sender.tag];
      NSString * urlStr = [[BASE_URLstringByAppendingString:DOWNLOAD_CHECKLIST_METADATA_SUBURL] stringByAppendingFormat:@"%@/%d/%@/%@/%@",[ChecklistSingleton sharedSingleton].userSSO,[check5.checklistId intValue],check5.language,check5.baseFormId,check5.versionNo];
      NSURL * url = [NSURL URLWithString:urlStr];
      NSLog(@"url is %@",url);
      NSURLSessionConfiguration *config = [NSURLSessionConfiguration  defaultSessionConfiguration];
      NSURLSession *session = [NSURLSession sessionWithConfiguration:config];
    
      NSMutableURLRequest * request = [[NSMutableURLRequest alloc] initWithURL:url];
    AppDelegate * appDelegateObj = (AppDelegate *)[[UIApplication sharedApplication] delegate];
     [request setValue:[NSString stringWithFormat:@"Bearer %@",appDelegateObj.accessToken ]forHTTPHeaderField:@"Authorization"];
     [request setTimeoutInterval:240.0];
     [request setValue:@"Application/JSON" forHTTPHeaderField:@"Content-Type"];
    NSURLSessionDataTask * downloadTask =[session dataTaskWithRequest:request completionHandler:^(NSData * data, NSURLResponse * response, NSError * error)
                                          {
                                              // 4 - add index of downloaded checklist
                                              [indexSet addIndex:sender.tag];
                                              //5 - remove all checklists if all of them are downloaded
                                              if([indexSet count]==[tempArray count])
                                                     [tempArray removeAllObjects];
                                              NSString * str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
                                              NSLog(@"response is specific %@",str);
    
                                              //6 - enable the button
                                              sender.enabled = YES;
    
                                          }];
    [downloadTask resume];
    
    }