Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NSOperation Queue behaving abnormally

I have a task of uploading multiple images to the server one by one. So I am using the batch operation process for this. Every time I start the upload procedure, some operations specially the first one completes as soon as it starts and the image does not get uploaded, and then the batch upoad process continues fine with a rare glitch of missing the other images.

The code I am using is as follows:-

-(void)callWSToUploadRxs{


    NSLog(@"the total assets maintained are %lu", (unsigned long)_arr_assetsMaintained.count);

    NSMutableArray *mutableOperations = [NSMutableArray array];
    int imageUploadCount = (int)[self extractFullSizeImagesToUpload].count;
    // second for loop is to initialize the operations and then queue them.
    for (int i = 0; i<imageUploadCount; i++) {


        NSData *imageData = UIImageJPEGRepresentation([_arr_originalImagesToSend objectAtIndex:i],1.0);

        NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
        [request setHTTPMethod:@"POST"];

        NSLog(@"the url constructed is %@", [NSString stringWithFormat:@"%@/%@/%@/%@",uploadRxUrl,@"4004DD85-1421-4992-A811-8E2F3B2E49F7",@"5293",[_arr_imageNames objectAtIndex:i]]);
        [request setURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@/%@/%@/%@.jpg",uploadRxUrl,@"4004DD85-1421-4992-A811-8E2F3B2E49F7",@"5293",[_arr_imageNames objectAtIndex:i]]]];
        [request setValue:@"binary/octet-stream" forHTTPHeaderField:@"Content-Type"];

        [request setHTTPBody:imageData];
        AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];

        [mutableOperations addObject:operation];
    }

    currentUploadIndex++;
    NSArray *operations = [AFURLConnectionOperation batchOfRequestOperations:mutableOperations progressBlock:^(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations) {
        NSLog(@"%lu of %lu complete", numberOfFinishedOperations, totalNumberOfOperations);

        NSIndexPath * indexOfImageTobeDeleted = [_selectedItemsIndexPaths objectAtIndex:0];//numberOfFinishedOperations-1
        [_arr_assetsMaintained removeObjectAtIndex:indexOfImageTobeDeleted.item];
        [_arr_images removeObjectAtIndex:indexOfImageTobeDeleted.item];
        [_arr_fullSizeImages removeObjectAtIndex:indexOfImageTobeDeleted.item];
        [_arr_imageNames removeObjectAtIndex:indexOfImageTobeDeleted.item];

        if ( [_arr_selectedCells containsObject:[NSString stringWithFormat:@"%ld",(long)indexOfImageTobeDeleted.item]]  )
        {
            [_arr_selectedCells removeObject:[NSString stringWithFormat:@"%ld",(long)indexOfImageTobeDeleted.item]];
            //[cell.img_selctedRxs setHidden:TRUE];


        }
        countBeforeClearingAssets = countBeforeClearingAssets - 1;
        //Reload the items of UICollectionView performBatchUpdates Block
        [_albumImagesCollection performBatchUpdates:^{
            [_albumImagesCollection deleteItemsAtIndexPaths:@[indexOfImageTobeDeleted]];
        } completion:nil];

        _selectedItemsIndexPaths = [_albumImagesCollection indexPathsForSelectedItems];
       // [_selectedItemsIndexPaths removeObjectAtIndex:0];
        NSLog(@"the count of selected items after updation is %lu", (unsigned long)_selectedItemsIndexPaths.count);


    } completionBlock:^(NSArray *operations) {
        NSLog(@"All operations in batch complete");
        [self callWSToAddNoteForRxs];
        [_arr_originalImagesToSend removeAllObjects];
        [_arr_selectedCells removeAllObjects];
        currentUploadIndex = 0;
        NSLog(@"the array of image names is %@",_arr_imageNames);
    }];

    [[NSOperationQueue mainQueue] addOperations:operations waitUntilFinished:NO];

    // third is to maintain the progress block for each image to be uploaded one after the other.
    for (AFHTTPRequestOperation *operation in mutableOperations){

        [operation setUploadProgressBlock:^(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite) {

            [_progressOverLayView setAlpha:0.7f];
            [_progressView setHidden:FALSE];
            [_progressView setProgress: totalBytesWritten*1.0f / totalBytesExpectedToWrite animated: YES];
            [_lbl_progressUpdate setHidden:FALSE];
            _lbl_progressUpdate.text = [NSString stringWithFormat:@"Image %d of %lu uploading", currentUploadIndex, mutableOperations.count];
            NSLog(@"Sent %lld of %lld bytes and progress is %f", totalBytesWritten, totalBytesExpectedToWrite, totalBytesWritten*1.0f /  totalBytesExpectedToWrite);
            if(totalBytesWritten >= totalBytesExpectedToWrite)
            {
                //progressView.hidden = YES;
                [self setComplete];
            }
        }];
    }

}

In this code, the first operation is getting executed as soon I start uploading the images i.e only 3 out of 4 are getting uploaded. One Image is always left out. Also. if I do have only Image in the grid, that uploads successfully.

Thanks.

like image 552
Shikhar varshney Avatar asked Dec 21 '15 08:12

Shikhar varshney


1 Answers

A few thoughts...

1) the progress update block. This doesn't tell you which operations completed; only the count of them, so I am suspicious that they might not be completing in the order the code thinks they are all the time....

2) the completion block takes an array of operations.... I wonder if this gets called once with all of the operations, or multiple times with arrays of the operations that completed? You could look at the array length to see. If it does get called for subsets of operations, this would be the place to remove the assets that have already been uploaded and do cleanup work, since you know which operations finished.

3) I would set the upload progress block before adding the operations to the queue; just for safety.

4) I couldn't find documentation for the batchOperation method, and wondered if it has been removed from a more recent version of AFNetworking - and if so - maybe it's buggy or not good API? I'd be tempted to create my own operations in a loop for clarity; and then do a little state management to check on the status of the batch and handle that appropriately.

5) You say one image is always left out.... is it stable - always the first or last? Does it behave the same way on the sim vs on a cell network or simulated slow / unreliable connection??

like image 137
Fiid Avatar answered Sep 21 '22 20:09

Fiid