How To Update ProgressView in Async Thread

时间秒杀一切 提交于 2019-12-12 04:49:26

问题


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.


回答1:


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]));




回答2:


You should create and update `UIProgressView' on main queue

and do your work on another queue (not main queue)

And while doing your work, if you want to update any object on GUI, you should do it on main queue

You can do like this:

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;

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 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];

            dispatch_async(dispatch_get_main_queue(), ^{
                prgView.progress =((float) i /([fileLinks count]));
            });
            NSLog(@" progress value is %f", prgView.progress);
        }
    });

You can read an ebook: "Pro.Multithreading.and.Memory.Management.for.iOS.and.OS.X" (buy or ask gg)

Good luck!




回答3:


Combination of async and sync is right, but combination of main thread and other thread cause cycle, especially in async thread using sync main thread.



来源:https://stackoverflow.com/questions/17919085/how-to-update-progressview-in-async-thread

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!