Search code examples
iosnsoperationnsoperationqueue

NSOperationQueue not running all the operations


I am using NSOperationQueue to perform concurrent download and to insert into Core Data.

Following is the code, I am using

if(nil==queue)
{
    queue=[[NSOperationQueue alloc]init];
   [queue setMaxConcurrentOperationCount:5];
}
for (FileDetailsEntity *entity in array)
{
    InoFileDownloader *fileDownloader=[[InoFileDownloader alloc]initWithFileDetailsEntity:entity andDelegate:self];
    [queue addOperation:fileDownloader];
}


//InoFiledownloader.m file

- (void)mergeChanges:(NSNotification *)notification
 {
    appDelegate=(InoAppDelegate*)[[UIApplication sharedApplication]delegate];
    NSManagedObjectContext *mainContext = [appDelegate managedObjectContext];

// Merge changes into the main context on the main thread
[mainContext performSelectorOnMainThread:@selector(mergeChangesFromContextDidSaveNotification:)
                              withObject:notification
                           waitUntilDone:YES];
}


-(void)start
 {
    @autoreleasepool {


    [self willChangeValueForKey:@"isExecuting"];
    self.isExecuting = YES;
    [self didChangeValueForKey:@"isExecuting"];

    appDelegate=(InoAppDelegate*)[[UIApplication sharedApplication]delegate];

    NSManagedObjectContext *ctx = [[NSManagedObjectContext alloc] init];
    [ctx setUndoManager:nil];
    [ctx setPersistentStoreCoordinator: [appDelegate persistentStoreCoordinator]];


    // Register context with the notification center
    NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
    [nc addObserver:self
           selector:@selector(mergeChanges:)
               name:NSManagedObjectContextDidSaveNotification
             object:ctx];

    NSDictionary *taskID=[[NSDictionary alloc]initWithObjectsAndKeys:fileDetaislsEntity.fileId,@"fileId",nil];

    NSArray *arry=[[NSArray alloc]initWithObjects:taskID, nil];

    NSMutableDictionary *jsonRequest=[NSMutableDictionary new];

    [jsonRequest setValue:arry forKey:@"fileId"];

    jsonWriter = [[SBJsonWriter alloc] init];

    if(self.isCancelled)
        return;

    NSString *jsonString = [jsonWriter stringWithObject:jsonRequest];

    NSData *postData = [jsonString dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
    NSString *postLength = [NSString stringWithFormat:@"%d", [postData length]];

    if(self.isCancelled)
        return;


    NSURL *url = [NSURL URLWithString:@"http://192.168.4.247:8080/InnoApps/mobjobs/post/imageDownload"];

    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
    [request setURL:url];
    [request setHTTPMethod:@"POST"];
    [request setValue:postLength forHTTPHeaderField:@"Content-Length"];
    [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];

    if(self.isCancelled)
        return;

    [request setHTTPBody:postData];
    NSHTTPURLResponse* response;
    NSError* error = nil;

    //  NSLog(@"File started to download for the file id %@",entity.fileId);

    if(self.isCancelled)
        return;

    //Capturing server response
    NSLog(@"started to download for file id--%@",fileDetaislsEntity.fileId);
    NSData* result = [NSURLConnection sendSynchronousRequest:request  returningResponse:&response error:&error];
    NSLog(@"finished downloading data for file id--%@",fileDetaislsEntity.fileId);
    // if(request)
    //     NSLog(@"File downloaded for the file id %@",entity.fileId);

    if(self.isCancelled)
        return;

    SBJSON *jsonParser=[SBJSON new];

    NSString *jsonStr=[[NSString alloc]initWithData:result encoding:NSUTF8StringEncoding];


    // if(response.statusCode!=0)
    NSDictionary *resultDic;

    if([response statusCode]!=0)
    {
        resultDic= [jsonParser objectWithString:jsonStr];
    }
    else
    {
        resultDic=nil;
    }

    //  NSLog(@"resultDic---%@",resultDic);

    NSMutableDictionary *imageDetails= [[resultDic objectForKey:@"image"] objectAtIndex:0];
    NSString *imageStr=[imageDetails objectForKey:@"imageBlob"];


    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription
                                   entityForName:@"FileDetailsEntity" inManagedObjectContext:ctx];

    [fetchRequest setEntity:entity];
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"taskId = %@ AND fileId=%@",fileDetaislsEntity.taskId,fileDetaislsEntity.fileId];

    [fetchRequest setPredicate:predicate];

    NSError *errorTmp=nil;
    NSArray *fileDetailsArray= [ctx executeFetchRequest:fetchRequest error:&error];

    if(errorTmp)
        NSLog(@"error in fetching filedetails array----%@",[errorTmp localizedDescription]);
    for(FileDetailsEntity *entity in fileDetailsArray)
    {
        [entity setFileData:[imageStr dataUsingEncoding:NSUTF8StringEncoding]];
    }




    if(self.isCancelled)
        return;

    NSError *errorForDataSaving;

    if(![ctx save:&errorForDataSaving])
        NSLog(@"failed to save data after downloading image ---%@",[error localizedDescription]);

    NSLog(@"data saved in db for file id--%@",fileDetaislsEntity.fileId);

    if(self.isCancelled)
        return;


    [self willChangeValueForKey:@"isFinished"];
    [self willChangeValueForKey:@"isExecuting"];
    isExecuting = NO;
    isFinished = YES;
    [self didChangeValueForKey:@"isExecuting"];
    [self didChangeValueForKey:@"isFinished"];

    [(NSObject*)self.delegate performSelectorOnMainThread:@selector(didFinishDownloadingFileWithFileId:) withObject:fileDetaislsEntity.fileId waitUntilDone:NO];



}

}


 -(BOOL)isConcurrent { return YES; }

 -(BOOL)isExecuting { return isExecuting; }

 -(BOOL)isFinished { return isFinished; }

 -(BOOL)isCancelled { return cancelled; }

Only it runs maximum of 15 or 20 operations after that, the queue is not running. Can someone tell me. what is going wrong.


Solution

  • The problem might well be that you are using NSURLConnection sendSynchronousRequest. This is nearly always a bad idea, because it blocks, which means, among other things, that it can bring your code to a complete halt (which sounds like exactly what is happening).

    People typically use NSURLConnection sendSynchronousRequest because they are afraid or don't know how to use NSURLConnection properly, i.e. asynchronously. But it is not difficult to use properly, and it's worth doing.