123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262 |
- // AFNetworkActivityIndicatorManager.m
- // Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to deal
- // in the Software without restriction, including without limitation the rights
- // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- // copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- // THE SOFTWARE.
- #import "AFNetworkActivityIndicatorManager.h"
- #if TARGET_OS_IOS
- #import "AFURLSessionManager.h"
- typedef NS_ENUM(NSInteger, AFNetworkActivityManagerState) {
- AFNetworkActivityManagerStateNotActive,
- AFNetworkActivityManagerStateDelayingStart,
- AFNetworkActivityManagerStateActive,
- AFNetworkActivityManagerStateDelayingEnd
- };
- static NSTimeInterval const kDefaultAFNetworkActivityManagerActivationDelay = 1.0;
- static NSTimeInterval const kDefaultAFNetworkActivityManagerCompletionDelay = 0.17;
- static NSURLRequest * AFNetworkRequestFromNotification(NSNotification *notification) {
- if ([[notification object] respondsToSelector:@selector(originalRequest)]) {
- return [(NSURLSessionTask *)[notification object] originalRequest];
- } else {
- return nil;
- }
- }
- typedef void (^AFNetworkActivityActionBlock)(BOOL networkActivityIndicatorVisible);
- @interface AFNetworkActivityIndicatorManager ()
- @property (readwrite, nonatomic, assign) NSInteger activityCount;
- @property (readwrite, nonatomic, strong) NSTimer *activationDelayTimer;
- @property (readwrite, nonatomic, strong) NSTimer *completionDelayTimer;
- @property (readonly, nonatomic, getter = isNetworkActivityOccurring) BOOL networkActivityOccurring;
- @property (nonatomic, copy) AFNetworkActivityActionBlock networkActivityActionBlock;
- @property (nonatomic, assign) AFNetworkActivityManagerState currentState;
- @property (nonatomic, assign, getter=isNetworkActivityIndicatorVisible) BOOL networkActivityIndicatorVisible;
- - (void)updateCurrentStateForNetworkActivityChange;
- @end
- @implementation AFNetworkActivityIndicatorManager
- + (instancetype)sharedManager {
- static AFNetworkActivityIndicatorManager *_sharedManager = nil;
- static dispatch_once_t oncePredicate;
- dispatch_once(&oncePredicate, ^{
- _sharedManager = [[self alloc] init];
- });
- return _sharedManager;
- }
- - (instancetype)init {
- self = [super init];
- if (!self) {
- return nil;
- }
- self.currentState = AFNetworkActivityManagerStateNotActive;
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkRequestDidStart:) name:AFNetworkingTaskDidResumeNotification object:nil];
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkRequestDidFinish:) name:AFNetworkingTaskDidSuspendNotification object:nil];
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkRequestDidFinish:) name:AFNetworkingTaskDidCompleteNotification object:nil];
- self.activationDelay = kDefaultAFNetworkActivityManagerActivationDelay;
- self.completionDelay = kDefaultAFNetworkActivityManagerCompletionDelay;
- return self;
- }
- - (void)dealloc {
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- [_activationDelayTimer invalidate];
- [_completionDelayTimer invalidate];
- }
- - (void)setEnabled:(BOOL)enabled {
- _enabled = enabled;
- if (enabled == NO) {
- [self setCurrentState:AFNetworkActivityManagerStateNotActive];
- }
- }
- - (void)setNetworkingActivityActionWithBlock:(void (^)(BOOL networkActivityIndicatorVisible))block {
- self.networkActivityActionBlock = block;
- }
- - (BOOL)isNetworkActivityOccurring {
- @synchronized(self) {
- return self.activityCount > 0;
- }
- }
- - (void)setNetworkActivityIndicatorVisible:(BOOL)networkActivityIndicatorVisible {
- if (_networkActivityIndicatorVisible != networkActivityIndicatorVisible) {
- [self willChangeValueForKey:@"networkActivityIndicatorVisible"];
- @synchronized(self) {
- _networkActivityIndicatorVisible = networkActivityIndicatorVisible;
- }
- [self didChangeValueForKey:@"networkActivityIndicatorVisible"];
- if (self.networkActivityActionBlock) {
- self.networkActivityActionBlock(networkActivityIndicatorVisible);
- } else {
- [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:networkActivityIndicatorVisible];
- }
- }
- }
- - (void)setActivityCount:(NSInteger)activityCount {
- @synchronized(self) {
- _activityCount = activityCount;
- }
- dispatch_async(dispatch_get_main_queue(), ^{
- [self updateCurrentStateForNetworkActivityChange];
- });
- }
- - (void)incrementActivityCount {
- [self willChangeValueForKey:@"activityCount"];
- @synchronized(self) {
- _activityCount++;
- }
- [self didChangeValueForKey:@"activityCount"];
- dispatch_async(dispatch_get_main_queue(), ^{
- [self updateCurrentStateForNetworkActivityChange];
- });
- }
- - (void)decrementActivityCount {
- [self willChangeValueForKey:@"activityCount"];
- @synchronized(self) {
- #pragma clang diagnostic push
- #pragma clang diagnostic ignored "-Wgnu"
- _activityCount = MAX(_activityCount - 1, 0);
- #pragma clang diagnostic pop
- }
- [self didChangeValueForKey:@"activityCount"];
- dispatch_async(dispatch_get_main_queue(), ^{
- [self updateCurrentStateForNetworkActivityChange];
- });
- }
- - (void)networkRequestDidStart:(NSNotification *)notification {
- if ([AFNetworkRequestFromNotification(notification) URL]) {
- [self incrementActivityCount];
- }
- }
- - (void)networkRequestDidFinish:(NSNotification *)notification {
- if ([AFNetworkRequestFromNotification(notification) URL]) {
- [self decrementActivityCount];
- }
- }
- #pragma mark - Internal State Management
- - (void)setCurrentState:(AFNetworkActivityManagerState)currentState {
- @synchronized(self) {
- if (_currentState != currentState) {
- [self willChangeValueForKey:@"currentState"];
- _currentState = currentState;
- switch (currentState) {
- case AFNetworkActivityManagerStateNotActive:
- [self cancelActivationDelayTimer];
- [self cancelCompletionDelayTimer];
- [self setNetworkActivityIndicatorVisible:NO];
- break;
- case AFNetworkActivityManagerStateDelayingStart:
- [self startActivationDelayTimer];
- break;
- case AFNetworkActivityManagerStateActive:
- [self cancelCompletionDelayTimer];
- [self setNetworkActivityIndicatorVisible:YES];
- break;
- case AFNetworkActivityManagerStateDelayingEnd:
- [self startCompletionDelayTimer];
- break;
- }
- }
- [self didChangeValueForKey:@"currentState"];
- }
- }
- - (void)updateCurrentStateForNetworkActivityChange {
- if (self.enabled) {
- switch (self.currentState) {
- case AFNetworkActivityManagerStateNotActive:
- if (self.isNetworkActivityOccurring) {
- [self setCurrentState:AFNetworkActivityManagerStateDelayingStart];
- }
- break;
- case AFNetworkActivityManagerStateDelayingStart:
- //No op. Let the delay timer finish out.
- break;
- case AFNetworkActivityManagerStateActive:
- if (!self.isNetworkActivityOccurring) {
- [self setCurrentState:AFNetworkActivityManagerStateDelayingEnd];
- }
- break;
- case AFNetworkActivityManagerStateDelayingEnd:
- if (self.isNetworkActivityOccurring) {
- [self setCurrentState:AFNetworkActivityManagerStateActive];
- }
- break;
- }
- }
- }
- - (void)startActivationDelayTimer {
- self.activationDelayTimer = [NSTimer
- timerWithTimeInterval:self.activationDelay target:self selector:@selector(activationDelayTimerFired) userInfo:nil repeats:NO];
- [[NSRunLoop mainRunLoop] addTimer:self.activationDelayTimer forMode:NSRunLoopCommonModes];
- }
- - (void)activationDelayTimerFired {
- if (self.networkActivityOccurring) {
- [self setCurrentState:AFNetworkActivityManagerStateActive];
- } else {
- [self setCurrentState:AFNetworkActivityManagerStateNotActive];
- }
- }
- - (void)startCompletionDelayTimer {
- [self.completionDelayTimer invalidate];
- self.completionDelayTimer = [NSTimer timerWithTimeInterval:self.completionDelay target:self selector:@selector(completionDelayTimerFired) userInfo:nil repeats:NO];
- [[NSRunLoop mainRunLoop] addTimer:self.completionDelayTimer forMode:NSRunLoopCommonModes];
- }
- - (void)completionDelayTimerFired {
- [self setCurrentState:AFNetworkActivityManagerStateNotActive];
- }
- - (void)cancelActivationDelayTimer {
- [self.activationDelayTimer invalidate];
- }
- - (void)cancelCompletionDelayTimer {
- [self.completionDelayTimer invalidate];
- }
- @end
- #endif
|