Use lightweight locking for activityCount

Also exposes isNetworkActivityIndicatorVisible which now is KVO observable.
This commit is contained in:
Peter Steinberger 2012-04-05 17:29:18 -07:00
parent 0470f4b29f
commit 069615a20d
2 changed files with 27 additions and 26 deletions

View file

@ -30,12 +30,7 @@
/** /**
`AFNetworkActivityIndicatorManager` manages the state of the network activity indicator in the status bar. When enabled, it will listen for notifications indicating that a network request operation has started or finished, and start or stop animating the indicator accordingly. The number of active requests is incremented and decremented much like a stack or a semaphore, and the activity indicator will animate so long as that number is greater than zero. `AFNetworkActivityIndicatorManager` manages the state of the network activity indicator in the status bar. When enabled, it will listen for notifications indicating that a network request operation has started or finished, and start or stop animating the indicator accordingly. The number of active requests is incremented and decremented much like a stack or a semaphore, and the activity indicator will animate so long as that number is greater than zero.
*/ */
@interface AFNetworkActivityIndicatorManager : NSObject { @interface AFNetworkActivityIndicatorManager : NSObject;
@private
NSInteger _activityCount;
BOOL _enabled;
NSTimer *_activityIndicatorVisibilityTimer;
}
/** /**
A Boolean value indicating whether the manager is enabled. A Boolean value indicating whether the manager is enabled.
@ -61,6 +56,11 @@
*/ */
- (void)decrementActivityCount; - (void)decrementActivityCount;
/**
Returns the network indicator visibility. This is more excact than polling [UIApplication sharedApplication] isNetworkActivityIndicatorVisible] since we add a slight delay while updating the indicator to avoid flickering. You can observe this via KVO.
*/
- (BOOL)isNetworkActivityIndicatorVisible;
@end @end
#endif #endif

View file

@ -23,6 +23,7 @@
#import "AFNetworkActivityIndicatorManager.h" #import "AFNetworkActivityIndicatorManager.h"
#import "AFHTTPRequestOperation.h" #import "AFHTTPRequestOperation.h"
#import <libkern/OSAtomic.h>
#if __IPHONE_OS_VERSION_MIN_REQUIRED #if __IPHONE_OS_VERSION_MIN_REQUIRED
static NSTimeInterval const kAFNetworkActivityIndicatorInvisibilityDelay = 0.25; static NSTimeInterval const kAFNetworkActivityIndicatorInvisibilityDelay = 0.25;
@ -30,7 +31,6 @@ static NSTimeInterval const kAFNetworkActivityIndicatorInvisibilityDelay = 0.25;
@interface AFNetworkActivityIndicatorManager () @interface AFNetworkActivityIndicatorManager ()
@property (readwrite, nonatomic, assign) NSInteger activityCount; @property (readwrite, nonatomic, assign) NSInteger activityCount;
@property (readwrite, nonatomic, retain) NSTimer *activityIndicatorVisibilityTimer; @property (readwrite, nonatomic, retain) NSTimer *activityIndicatorVisibilityTimer;
@property (readwrite, nonatomic, retain) NSRecursiveLock *lock;
@property (readonly, getter = isNetworkActivityIndicatorVisible) BOOL networkActivityIndicatorVisible; @property (readonly, getter = isNetworkActivityIndicatorVisible) BOOL networkActivityIndicatorVisible;
- (void)updateNetworkActivityIndicatorVisibility; - (void)updateNetworkActivityIndicatorVisibility;
@ -39,7 +39,6 @@ static NSTimeInterval const kAFNetworkActivityIndicatorInvisibilityDelay = 0.25;
@implementation AFNetworkActivityIndicatorManager @implementation AFNetworkActivityIndicatorManager
@synthesize activityCount = _activityCount; @synthesize activityCount = _activityCount;
@synthesize activityIndicatorVisibilityTimer = _activityIndicatorVisibilityTimer; @synthesize activityIndicatorVisibilityTimer = _activityIndicatorVisibilityTimer;
@synthesize lock = _lock;
@synthesize enabled = _enabled; @synthesize enabled = _enabled;
@dynamic networkActivityIndicatorVisible; @dynamic networkActivityIndicatorVisible;
@ -59,8 +58,6 @@ static NSTimeInterval const kAFNetworkActivityIndicatorInvisibilityDelay = 0.25;
return nil; return nil;
} }
self.lock = [[[NSRecursiveLock alloc] init] autorelease];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(incrementActivityCount) name:AFNetworkingOperationDidStartNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(incrementActivityCount) name:AFNetworkingOperationDidStartNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(decrementActivityCount) name:AFNetworkingOperationDidFinishNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(decrementActivityCount) name:AFNetworkingOperationDidFinishNotification object:nil];
@ -73,17 +70,10 @@ static NSTimeInterval const kAFNetworkActivityIndicatorInvisibilityDelay = 0.25;
[_activityIndicatorVisibilityTimer invalidate]; [_activityIndicatorVisibilityTimer invalidate];
[_activityIndicatorVisibilityTimer release]; _activityIndicatorVisibilityTimer = nil; [_activityIndicatorVisibilityTimer release]; _activityIndicatorVisibilityTimer = nil;
[_lock release];
[super dealloc]; [super dealloc];
} }
- (void)setActivityCount:(NSInteger)activityCount { - (void)updateNetworkActivityIndicatorVisibilityDelayed {
[self.lock lock];
[self willChangeValueForKey:@"activityCount"];
_activityCount = MAX(activityCount, 0);
[self didChangeValueForKey:@"activityCount"];
if (self.enabled) { if (self.enabled) {
// Delay hiding of activity indicator for a short interval, to avoid flickering // Delay hiding of activity indicator for a short interval, to avoid flickering
if (![self isNetworkActivityIndicatorVisible]) { if (![self isNetworkActivityIndicatorVisible]) {
@ -94,11 +84,10 @@ static NSTimeInterval const kAFNetworkActivityIndicatorInvisibilityDelay = 0.25;
[self updateNetworkActivityIndicatorVisibility]; [self updateNetworkActivityIndicatorVisibility];
} }
} }
[self.lock unlock];
} }
- (BOOL)isNetworkActivityIndicatorVisible { - (BOOL)isNetworkActivityIndicatorVisible {
return self.activityCount > 0; return _activityCount > 0;
} }
- (void)updateNetworkActivityIndicatorVisibility { - (void)updateNetworkActivityIndicatorVisibility {
@ -107,16 +96,28 @@ static NSTimeInterval const kAFNetworkActivityIndicatorInvisibilityDelay = 0.25;
}); });
} }
// not actually exposed, but will be used if someone tries to set activityCount via KVC.
- (void)setActivityCount:(NSInteger)activityCount {
__sync_swap(&_activityCount, activityCount);
[self updateNetworkActivityIndicatorVisibilityDelayed];
}
- (void)incrementActivityCount { - (void)incrementActivityCount {
[self.lock lock]; [self willChangeValueForKey:@"activityCount"];
self.activityCount += 1; OSAtomicIncrement32((int32_t*)&_activityCount);
[self.lock unlock]; [self didChangeValueForKey:@"activityCount"];
[self updateNetworkActivityIndicatorVisibilityDelayed];
} }
- (void)decrementActivityCount { - (void)decrementActivityCount {
[self.lock lock]; [self willChangeValueForKey:@"activityCount"];
self.activityCount -= 1; OSAtomicDecrement32((int32_t*)&_activityCount);
[self.lock unlock]; [self didChangeValueForKey:@"activityCount"];
[self updateNetworkActivityIndicatorVisibilityDelayed];
}
+ (NSSet *)keyPathsForValuesAffectingIsNetworkActivityIndicatorVisible {
return [NSSet setWithObject:@"activityCount"];
} }
@end @end