You're attempting to update the progress view 1000 times in 1.5 seconds. That's way too fast, since the screen only updates 60 times per second. In other words, you're updating the progress bar more than 10 times between each time that the progress bar is actually redrawn on the screen.
Instead I would suggest 15 updates at 0.1 second intervals, and change the progress bar by 1/15 each time.
One way to check how well the code is performing is to use the CACurrentMediaTime
function to get timestamps. Here's some sample code that demonstrates how to do that. The progressStart
variable is the timestamp when the button press event occurred, and the NSLog
prints the amount of time elapsed relative to the start time.
An important feature of the code is that the performSelector
method is called as early as possible in the updateProgress
method, to minimize slippage.
@interface ViewController ()
{
CFTimeInterval progressStart;
int progressCount;
}
@property (weak, nonatomic) IBOutlet UIProgressView *progressView;
@end
- (void)updateProgress
{
if ( progressCount > 0 )
[self performSelector:@selector(updateProgress) withObject:nil afterDelay:0.1];
self.progressView.progress = progressCount / 15.0;
NSLog( @"%2d %.3lf", progressCount, CACurrentMediaTime() - progressStart );
progressCount--;
}
- (IBAction)someButtonPressed
{
self.progressView.progress = 1.0;
progressStart = CACurrentMediaTime();
progressCount = 15;
[self updateProgress];
}
And here are the results from a typical run
2015-07-01 13:05:57.610 Progress[8354:907] 15 0.000
2015-07-01 13:05:57.711 Progress[8354:907] 14 0.101
2015-07-01 13:05:57.813 Progress[8354:907] 13 0.203
2015-07-01 13:05:57.914 Progress[8354:907] 12 0.304
2015-07-01 13:05:58.015 Progress[8354:907] 11 0.405
2015-07-01 13:05:58.116 Progress[8354:907] 10 0.506
2015-07-01 13:05:58.218 Progress[8354:907] 9 0.608
2015-07-01 13:05:58.319 Progress[8354:907] 8 0.709
2015-07-01 13:05:58.420 Progress[8354:907] 7 0.810
2015-07-01 13:05:58.520 Progress[8354:907] 6 0.910
2015-07-01 13:05:58.621 Progress[8354:907] 5 1.011
2015-07-01 13:05:58.722 Progress[8354:907] 4 1.112
2015-07-01 13:05:58.823 Progress[8354:907] 3 1.213
2015-07-01 13:05:58.924 Progress[8354:907] 2 1.314
2015-07-01 13:05:59.024 Progress[8354:907] 1 1.415
2015-07-01 13:05:59.125 Progress[8354:907] 0 1.515
Note that the performSelector:afterDelay
method has about 1 millisecond of slippage on each event. The total slippage was 15 milliseconds. The device screen update rate is 60 frames/sec, which is 16.7 msec/frame. So the total slippage was less than one frame time, and won't be noticeable to the user.
As rmaddy pointed out in the comments, using an NSTimer
allows you to avoid most of the slippage. However, the last timer event could still slip by an arbitrary amount of time.