Reputation: 382
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.
Upvotes: 1
Views: 1887
Reputation: 788
you should suspend the queue before add operations and be su to resume the queue after that you finsh to add the operations pool...
try with this:
if(nil==queue)
{
queue=[[NSOperationQueue alloc]init];
[queue setMaxConcurrentOperationCount:5];
}
[queue setSuspended:YES];
for (FileDetailsEntity *entity in array)
{
InoFileDownloader *fileDownloader=[[InoFileDownloader alloc]initWithFileDetailsEntity:entity andDelegate:self];
[queue addOperation:fileDownloader];
}
[queue setSuspended:NO];
also in the merge changes method change to flag waitUntillDone to FALSE like this:
[mainContext performSelectorOnMainThread:@selector(mergeChangesFromContextDidSaveNotification:)
withObject:notification
waitUntilDone:FALSE];
Upvotes: 2
Reputation: 535944
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.
Upvotes: 0