RockandRoll RockandRoll - 3 months ago 12
iOS Question

How To Update ProgressView in Async Thread

I am having few doubts about Combinations of GCD and queues, in iOS. let me put those here

First. According to IOS6 programming cookbook, here is small code snippet for downloading images using async and sync. and its as below

dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);dispatch_async (concurrentQueue, ^ {
UIImage *image = nil;
dispatch_sync(concurrentQueue, ^ { /* download image here */ });
dispatch_sync(dispatch_get_main_queue, ^ { /* show the downloaded image here */ });
});


Second. I need to download few images from Url, meanwhile i need to update the progress view showing how many images have got downloaded. so i am using following code snippet

dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async (concurrentQueue, ^ { dispatch_sync(dispatch_get_main_queue, ^ { /* download image here and update progress view here */ });
});


kindly note that i am updating progress view on main thread. But my progress view is getting displayed after all images has been downloaded. i checked other links but was not pretty clear with the answers.not getting the reason for the problem. My code is as below.

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{dispatch_sync(dispatch_get_main_queue(), ^{
alert = [[UIAlertView alloc] initWithTitle:@"Please Wait Downloading reports..." message:nil delegate:self cancelButtonTitle:nil otherButtonTitles: nil] ;
prgView = [[UIProgressView alloc]initWithProgressViewStyle:UIProgressViewStyleBar];
prgView.frame = CGRectMake(10, 50, 270, 20);
[alert addSubview:prgView];
[alert show];
prgView.progress=0.0;
actual= 0.0;

for(NSInteger i=0; i<[fileLinks count];i++)
{

// [self downLoadFileFromUrl : fileLinks[i]: i ];
NSLog(@"Url is %@", fileLinks[i]);
NSLog(@"i value is %d", i);
NSData *imagedata = [NSData dataWithContentsOfURL:[NSURL URLWithString:fileLinks[i]]];
NSString * _filename= [fileLinks[i] lastPathComponent];
NSMutableString *filePath = [[NSMutableString alloc] initWithFormat:@"%@", [VSCore getTempFolder]];
[filePath appendString: _filename] ;
[imagedata writeToFile: filePath atomically:YES];
prgView.progress =((float) i /([fileLinks count]));
NSLog(@" progress value is %f", prgView.progress);

}
});
});


so what is problem here? and my other doubt is, if any one wants to hold the user (displaying progress view or activity indicator) while performing long processing task, can't they do that in main thread ? (provided they are displaying progress bar or activity indicator), why we have to use combination of async, sync with concurrent thread or main thread etc etc.

and i am bit confused with, for what scenario i had to use the proper combination of async, sync, main queue , concurrent queue, serial queue. if any one give explains me or provide me good link for understand The combinations of async , sync and 3 queue. that will be great.

Answer

If you take a closer look at your code you'll notice you're actually running everything in the main thread.

^{dispatch_sync(dispatch_get_main_queue(), ^{
       alert = [[UIAlertView alloc] initWithTitle:@"Please Wait Downloading reports..." message:nil delegate:self cancelButtonTitle:nil otherButtonTitles: nil] ;
       prgView = [[UIProgressView alloc]initWithProgressViewStyle:UIProgressViewStyleBar];
       prgView.frame = CGRectMake(10, 50, 270, 20);
       [alert addSubview:prgView];
       [alert show];
      prgView.progress=0.0;
       actual= 0.0;
       for(NSInteger i=0; i<[fileLinks count];i++)
       {

        //  [self downLoadFileFromUrl : fileLinks[i]: i ];
           NSLog(@"Url is %@", fileLinks[i]);
           NSLog(@"i value is %d", i);
           NSData *imagedata = [NSData dataWithContentsOfURL:[NSURL URLWithString:fileLinks[i]]];
           NSString * _filename=  [fileLinks[i] lastPathComponent];
           NSMutableString *filePath = [[NSMutableString alloc] initWithFormat:@"%@", [VSCore getTempFolder]];
           [filePath appendString: _filename] ;
           [imagedata writeToFile: filePath atomically:YES];
           prgView.progress =((float) i /([fileLinks count]));
           NSLog(@" progress value is %f", prgView.progress);

       }
   });

This is going to run the downloadFileFromUrl and the update of the progress view in the main thread (unless the downloadFileFromUrl is an async operations, which I don't know)

Basically you need to run the downloadFileFromUrl method in a secondary thread, then only run this bit on the main thread: prgView.progress =((float) i /([fileLinks count]));

Comments