From 91fe90f0f75cbfd14933f00c40e8cee17937b30c Mon Sep 17 00:00:00 2001 From: rowanbeentje Date: Sun, 9 May 2010 16:18:34 +0000 Subject: - Update task progress spinner to draw on the main thread rather than a background thread; should fix a number of issues logged by the crash reporter - Update indicator code to merged master incorporating our changes, reworked and improved --- Source/YRKSpinningProgressIndicator.m | 108 +++++++++++++++++++++++++++------- 1 file changed, 87 insertions(+), 21 deletions(-) (limited to 'Source/YRKSpinningProgressIndicator.m') diff --git a/Source/YRKSpinningProgressIndicator.m b/Source/YRKSpinningProgressIndicator.m index b9af4847..07e93863 100644 --- a/Source/YRKSpinningProgressIndicator.m +++ b/Source/YRKSpinningProgressIndicator.m @@ -34,7 +34,10 @@ @interface YRKSpinningProgressIndicator (YRKSpinningProgressIndicatorPrivate) +- (void)updateFrame:(NSTimer *)timer; - (void) animateInBackgroundThread; +- (void)actuallyStartAnimation; +- (void)actuallyStopAnimation; @end @@ -48,12 +51,11 @@ _position = 0; _numFins = 12; _isAnimating = NO; - _animationThread = nil; - _foreColor = nil; - _backColor = nil; + _isFadingOut = NO; _isIndeterminate = YES; _currentValue = 0.0; _maxValue = 100.0; + _usesThreadedAnimation = NO; } return self; } @@ -62,6 +64,7 @@ if (_foreColor) [_foreColor release]; if (_backColor) [_backColor release]; if (_isAnimating) [self stopAnimation:self]; + [super dealloc]; } @@ -70,12 +73,11 @@ [super viewDidMoveToWindow]; if ([self window] == nil) { - // No window? View hierarchy may be going away. Ensure animation is stopped. - [self stopAnimation:self]; + // No window? View hierarchy may be going away. Dispose timer to clear circular retain of timer to self to timer. + [self actuallyStopAnimation]; } else if (_isAnimating) { - [self stopAnimation:self]; - [self startAnimation:self]; + [self actuallyStartAnimation]; } } @@ -105,7 +107,6 @@ CGContextTranslateCTM(currentContext,[self bounds].size.width/2,[self bounds].size.height/2); if (_isIndeterminate) { - // do initial rotation to start place CGContextRotateCTM(currentContext, 3.14159*2/_numFins * _position); @@ -157,15 +158,23 @@ # pragma mark - # pragma mark Subclass -- (void)animate:(id)sender +- (void)updateFrame:(NSTimer *)timer; { - if(_position > 1) { + if(_position > 0) { _position--; } else { - _position = _numFins; + _position = _numFins - 1; + } + + if (_usesThreadedAnimation) { + // draw now instead of waiting for setNeedsDisplay (that's the whole reason + // we're animating from background thread) + [self display]; + } + else { + [self setNeedsDisplay:YES]; } - [self display]; } - (void) animateInBackgroundThread @@ -177,7 +186,7 @@ NSInteger poolFlushCounter = 0; do { - [self animate:nil]; + [self updateFrame:nil]; usleep(animationDelay); poolFlushCounter++; if (poolFlushCounter > 256) { @@ -194,23 +203,59 @@ { if (!_isIndeterminate) return; if (_isAnimating) return; + + [self actuallyStartAnimation]; _isAnimating = YES; - - _animationThread = [[NSThread alloc] initWithTarget:self selector:@selector(animateInBackgroundThread) object:nil]; - [_animationThread start]; } - (void)stopAnimation:(id)sender { + [self actuallyStopAnimation]; _isAnimating = NO; +} + +- (void)actuallyStartAnimation +{ + // Just to be safe kill any existing timer. + [self actuallyStopAnimation]; + + if ([self window]) { + // Why animate if not visible? viewDidMoveToWindow will re-call this method when needed. + if (_usesThreadedAnimation) { + _animationThread = [[NSThread alloc] initWithTarget:self selector:@selector(animateInBackgroundThread) object:nil]; + [_animationThread start]; + } + else { + _animationTimer = [[NSTimer timerWithTimeInterval:(NSTimeInterval)0.05 + target:self + selector:@selector(updateFrame:) + userInfo:nil + repeats:YES] retain]; + + [[NSRunLoop currentRunLoop] addTimer:_animationTimer forMode:NSRunLoopCommonModes]; + [[NSRunLoop currentRunLoop] addTimer:_animationTimer forMode:NSDefaultRunLoopMode]; + [[NSRunLoop currentRunLoop] addTimer:_animationTimer forMode:NSEventTrackingRunLoopMode]; + } + } +} + +- (void)actuallyStopAnimation +{ if (_animationThread) { + // we were using threaded animation [_animationThread cancel]; if (![_animationThread isFinished]) { [[NSRunLoop currentRunLoop] runMode:NSModalPanelRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.05]]; } - [_animationThread release], _animationThread = nil; + [_animationThread release]; + _animationThread = nil; } - + else if (_animationTimer) { + // we were using timer-based animation + [_animationTimer invalidate]; + [_animationTimer release]; + _animationTimer = nil; + } [self setNeedsDisplay:YES]; } @@ -277,7 +322,7 @@ { _isIndeterminate = isIndeterminate; if (!_isIndeterminate && _isAnimating) [self stopAnimation:self]; - [self displayIfNeeded]; + [self setNeedsDisplay:YES]; } - (double)doubleValue @@ -287,7 +332,10 @@ - (void)setDoubleValue:(double)doubleValue { - if (_isIndeterminate) _isIndeterminate = NO; + // Automatically put it into determinate mode if it's not already. + if (_isIndeterminate) { + [self setIndeterminate:NO]; + } _currentValue = doubleValue; [self setNeedsDisplay:YES]; } @@ -300,7 +348,25 @@ - (void)setMaxValue:(double)maxValue { _maxValue = maxValue; - [self displayIfNeeded]; + [self setNeedsDisplay:YES]; +} + +- (void)setUsesThreadedAnimation:(BOOL)useThreaded +{ + if (_usesThreadedAnimation != useThreaded) { + _usesThreadedAnimation = useThreaded; + + if (_isAnimating) { + // restart the timer to use the new mode + [self stopAnimation:self]; + [self startAnimation:self]; + } + } +} + +- (BOOL)usesThreadedAnimation +{ + return _usesThreadedAnimation; } @end -- cgit v1.2.3