Search code examples
iosuitableviewuiprogressview

ProgressView block on scroll table


I have an issue. I have a UITableView and a View with a UIProgressView and when i scroll the table, the progressview not refresh the progress value... Only when the scroll is finish, the progress refresh..

enter image description here

I have no clue why is this happening. I tried to refresh the progress with dispatch_async

dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){

//I don't know what i have to put here, maybe the NSTimer??

    dispatch_async(dispatch_get_main_queue(), ^(void){

        //here i set the value of the progress
    });

});

but nothing changes...


Solution

  • You're almost there!

    I've replicated your problem and fixed it.

    This is it without the fix, which is the problem I think you have (note that the progress indicator doesn't update while scrolling):

    enter image description here

    and this is it with the fix:

    enter image description here

    The problem is that the scrolling also occurs on the main thread and blocks it. To fix this you just need a small adjustment to your timer. After you initialise your timer, add this:

    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
    

    Here's some example minimal code:

    -(instancetype)init{
        self = [super init];
        if (self) {
            _progressSoFar = 0.0;
        }
        return self;
    }
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        self.progressIndicator.progress = 0.0;
        self.myTimer = [NSTimer scheduledTimerWithTimeInterval: 0.1 target: self selector: @selector(callAfterSomeTime:) userInfo: nil repeats: YES];
        [[NSRunLoop currentRunLoop] addTimer:self.myTimer forMode:NSRunLoopCommonModes];
        [self.myTimer fire];
    }
    
    -(void)callAfterSomeTime:(NSTimer *)timer {
        if (self.progressSoFar == 1.0) {
            [self.myTimer invalidate];
            return;
        }
    
        // Do anything intensive on a background thread (probably not needed)
        dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
            // Update the progress on the main thread
            dispatch_async(dispatch_get_main_queue(), ^{
                self.progressSoFar += 0.01;
                self.progressIndicator.progress = self.progressSoFar;
            });
        });
    }
    

    The scroll occurs in UITrackingRunLoopMode. You need to make sure that your timer is also in that mode. You shouldn't need any background thread stuff unless you do some fancy calculations but I've included it just in case. Just do any intensive stuff inside the global_queue call but before the main thread call.