문제

I want to illustrate the progress on MBProgressHUD item, but when i triger this method :

- (IBAction)signInBttn:(id)sender {

    MBProgressHUD *hudd = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
    hudd.mode = MBProgressHUDModeAnnularDeterminate;
    hudd.labelText = @"Loading";

    __block float value = 0;
    for (int j = 0; j<2000; j++) {
        dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

            for (int i = 0; i<20000 ; i++) {

            }
            value += 0.001;
            dispatch_async( dispatch_get_main_queue(), ^{
                hudd.progress = value;
            });

        });
    }        
}

hud appears fully to 100%. This is only for my information, I dont have idea how to create background task which calculate something and when he done with e.g. 40% the HUD is refreshing to 40% of his progress. I hope I made ​​myself clear, and if anyone has time to help improve my code, thanks a lot for any answers

도움이 되었습니까?

해결책

In this case, you can solve the problem by decoupling the updating of the counter from the updating of your HUD in your UI. Apple refers to this as "updating the state asynchronously" in WWDC 2012 video Asynchronous Design Patterns with Blocks, GCD, and XPC.

Generally this isn't necessary (most of the time the stuff we're doing asynchronously is slow enough that we don't have problems), but if doing something that is running faster than the UI can hope to keep up with, you create a "dispatch source" for this. I'm going to illustrate it with a UIProgressView, but the same applies to pretty much any UI:

// create source for which we'll be incrementing a counter,
// and tell it to run the event handler in the main loop
// (because we're going to be updating the UI)

dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0, dispatch_get_main_queue());

// specify what you want the even handler to do (i.e. update the HUD or progress bar)

dispatch_source_set_event_handler(source, ^{
    self.iterations += dispatch_source_get_data(source);
    [self.progressView setProgress: (float) self.iterations / kMaxIterations];
});

// start the dispatch source

dispatch_resume(source);

// now, initiate the process that will update the source

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

    for (long i = 0; i < kMaxIterations; i++)
    {
        // presumably, do something meaningful here

        // now increment counter (and the event handler will take care of the UI)

        dispatch_source_merge_data(source, 1);
    }

    // when all done, cancel the dispatch source

    dispatch_source_cancel(source);
});

In my example, iterations is just a long property:

@property (nonatomic) long iterations;

And I defined my kMaxIterations constant as follows:

static long const kMaxIterations = 10000000l;

다른 팁

First off, if you want to delay execution use dispatch_after: Apple Doc since it could be that Clang is optimizing your loop (i.e. by making it not exist).

Within that block call dispatch_sync on the main thread to update the UI, since dispatch_async is not guaranteed to execute 'evenly'. Something like this ought to work...

for (...) {
    dispatch_after(<some formula of i>, DEFAULT_PRIORITY, ^{
         dispatch_sync(MAIN_QUEUE, ^{ hudd.progress = value });
    }
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top