|
|
// 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) { @synchronized(self) { _networkActivityIndicatorVisible = networkActivityIndicatorVisible; } if (self.networkActivityActionBlock) { self.networkActivityActionBlock(networkActivityIndicatorVisible); } else { [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:networkActivityIndicatorVisible]; } }}
- (void)incrementActivityCount { @synchronized(self) { self.activityCount++; } dispatch_async(dispatch_get_main_queue(), ^{ [self updateCurrentStateForNetworkActivityChange]; });}
- (void)decrementActivityCount { @synchronized(self) { self.activityCount = MAX(_activityCount - 1, 0); } 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) { _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; } } }}
- (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
|