Sin descripción

AFNetworkActivityIndicatorManager.m 9.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. // AFNetworkActivityIndicatorManager.m
  2. // Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. #import "AFNetworkActivityIndicatorManager.h"
  22. #if TARGET_OS_IOS
  23. #import "AFURLSessionManager.h"
  24. typedef NS_ENUM(NSInteger, AFNetworkActivityManagerState) {
  25. AFNetworkActivityManagerStateNotActive,
  26. AFNetworkActivityManagerStateDelayingStart,
  27. AFNetworkActivityManagerStateActive,
  28. AFNetworkActivityManagerStateDelayingEnd
  29. };
  30. static NSTimeInterval const kDefaultAFNetworkActivityManagerActivationDelay = 1.0;
  31. static NSTimeInterval const kDefaultAFNetworkActivityManagerCompletionDelay = 0.17;
  32. static NSURLRequest * AFNetworkRequestFromNotification(NSNotification *notification) {
  33. if ([[notification object] respondsToSelector:@selector(originalRequest)]) {
  34. return [(NSURLSessionTask *)[notification object] originalRequest];
  35. } else {
  36. return nil;
  37. }
  38. }
  39. typedef void (^AFNetworkActivityActionBlock)(BOOL networkActivityIndicatorVisible);
  40. @interface AFNetworkActivityIndicatorManager ()
  41. @property (readwrite, nonatomic, assign) NSInteger activityCount;
  42. @property (readwrite, nonatomic, strong) NSTimer *activationDelayTimer;
  43. @property (readwrite, nonatomic, strong) NSTimer *completionDelayTimer;
  44. @property (readonly, nonatomic, getter = isNetworkActivityOccurring) BOOL networkActivityOccurring;
  45. @property (nonatomic, copy) AFNetworkActivityActionBlock networkActivityActionBlock;
  46. @property (nonatomic, assign) AFNetworkActivityManagerState currentState;
  47. @property (nonatomic, assign, getter=isNetworkActivityIndicatorVisible) BOOL networkActivityIndicatorVisible;
  48. - (void)updateCurrentStateForNetworkActivityChange;
  49. @end
  50. @implementation AFNetworkActivityIndicatorManager
  51. + (instancetype)sharedManager {
  52. static AFNetworkActivityIndicatorManager *_sharedManager = nil;
  53. static dispatch_once_t oncePredicate;
  54. dispatch_once(&oncePredicate, ^{
  55. _sharedManager = [[self alloc] init];
  56. });
  57. return _sharedManager;
  58. }
  59. - (instancetype)init {
  60. self = [super init];
  61. if (!self) {
  62. return nil;
  63. }
  64. self.currentState = AFNetworkActivityManagerStateNotActive;
  65. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkRequestDidStart:) name:AFNetworkingTaskDidResumeNotification object:nil];
  66. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkRequestDidFinish:) name:AFNetworkingTaskDidSuspendNotification object:nil];
  67. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkRequestDidFinish:) name:AFNetworkingTaskDidCompleteNotification object:nil];
  68. self.activationDelay = kDefaultAFNetworkActivityManagerActivationDelay;
  69. self.completionDelay = kDefaultAFNetworkActivityManagerCompletionDelay;
  70. return self;
  71. }
  72. - (void)dealloc {
  73. [[NSNotificationCenter defaultCenter] removeObserver:self];
  74. [_activationDelayTimer invalidate];
  75. [_completionDelayTimer invalidate];
  76. }
  77. - (void)setEnabled:(BOOL)enabled {
  78. _enabled = enabled;
  79. if (enabled == NO) {
  80. [self setCurrentState:AFNetworkActivityManagerStateNotActive];
  81. }
  82. }
  83. - (void)setNetworkingActivityActionWithBlock:(void (^)(BOOL networkActivityIndicatorVisible))block {
  84. self.networkActivityActionBlock = block;
  85. }
  86. - (BOOL)isNetworkActivityOccurring {
  87. @synchronized(self) {
  88. return self.activityCount > 0;
  89. }
  90. }
  91. - (void)setNetworkActivityIndicatorVisible:(BOOL)networkActivityIndicatorVisible {
  92. if (_networkActivityIndicatorVisible != networkActivityIndicatorVisible) {
  93. [self willChangeValueForKey:@"networkActivityIndicatorVisible"];
  94. @synchronized(self) {
  95. _networkActivityIndicatorVisible = networkActivityIndicatorVisible;
  96. }
  97. [self didChangeValueForKey:@"networkActivityIndicatorVisible"];
  98. if (self.networkActivityActionBlock) {
  99. self.networkActivityActionBlock(networkActivityIndicatorVisible);
  100. } else {
  101. [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:networkActivityIndicatorVisible];
  102. }
  103. }
  104. }
  105. - (void)setActivityCount:(NSInteger)activityCount {
  106. @synchronized(self) {
  107. _activityCount = activityCount;
  108. }
  109. dispatch_async(dispatch_get_main_queue(), ^{
  110. [self updateCurrentStateForNetworkActivityChange];
  111. });
  112. }
  113. - (void)incrementActivityCount {
  114. [self willChangeValueForKey:@"activityCount"];
  115. @synchronized(self) {
  116. _activityCount++;
  117. }
  118. [self didChangeValueForKey:@"activityCount"];
  119. dispatch_async(dispatch_get_main_queue(), ^{
  120. [self updateCurrentStateForNetworkActivityChange];
  121. });
  122. }
  123. - (void)decrementActivityCount {
  124. [self willChangeValueForKey:@"activityCount"];
  125. @synchronized(self) {
  126. #pragma clang diagnostic push
  127. #pragma clang diagnostic ignored "-Wgnu"
  128. _activityCount = MAX(_activityCount - 1, 0);
  129. #pragma clang diagnostic pop
  130. }
  131. [self didChangeValueForKey:@"activityCount"];
  132. dispatch_async(dispatch_get_main_queue(), ^{
  133. [self updateCurrentStateForNetworkActivityChange];
  134. });
  135. }
  136. - (void)networkRequestDidStart:(NSNotification *)notification {
  137. if ([AFNetworkRequestFromNotification(notification) URL]) {
  138. [self incrementActivityCount];
  139. }
  140. }
  141. - (void)networkRequestDidFinish:(NSNotification *)notification {
  142. if ([AFNetworkRequestFromNotification(notification) URL]) {
  143. [self decrementActivityCount];
  144. }
  145. }
  146. #pragma mark - Internal State Management
  147. - (void)setCurrentState:(AFNetworkActivityManagerState)currentState {
  148. @synchronized(self) {
  149. if (_currentState != currentState) {
  150. [self willChangeValueForKey:@"currentState"];
  151. _currentState = currentState;
  152. switch (currentState) {
  153. case AFNetworkActivityManagerStateNotActive:
  154. [self cancelActivationDelayTimer];
  155. [self cancelCompletionDelayTimer];
  156. [self setNetworkActivityIndicatorVisible:NO];
  157. break;
  158. case AFNetworkActivityManagerStateDelayingStart:
  159. [self startActivationDelayTimer];
  160. break;
  161. case AFNetworkActivityManagerStateActive:
  162. [self cancelCompletionDelayTimer];
  163. [self setNetworkActivityIndicatorVisible:YES];
  164. break;
  165. case AFNetworkActivityManagerStateDelayingEnd:
  166. [self startCompletionDelayTimer];
  167. break;
  168. }
  169. }
  170. [self didChangeValueForKey:@"currentState"];
  171. }
  172. }
  173. - (void)updateCurrentStateForNetworkActivityChange {
  174. if (self.enabled) {
  175. switch (self.currentState) {
  176. case AFNetworkActivityManagerStateNotActive:
  177. if (self.isNetworkActivityOccurring) {
  178. [self setCurrentState:AFNetworkActivityManagerStateDelayingStart];
  179. }
  180. break;
  181. case AFNetworkActivityManagerStateDelayingStart:
  182. //No op. Let the delay timer finish out.
  183. break;
  184. case AFNetworkActivityManagerStateActive:
  185. if (!self.isNetworkActivityOccurring) {
  186. [self setCurrentState:AFNetworkActivityManagerStateDelayingEnd];
  187. }
  188. break;
  189. case AFNetworkActivityManagerStateDelayingEnd:
  190. if (self.isNetworkActivityOccurring) {
  191. [self setCurrentState:AFNetworkActivityManagerStateActive];
  192. }
  193. break;
  194. }
  195. }
  196. }
  197. - (void)startActivationDelayTimer {
  198. self.activationDelayTimer = [NSTimer
  199. timerWithTimeInterval:self.activationDelay target:self selector:@selector(activationDelayTimerFired) userInfo:nil repeats:NO];
  200. [[NSRunLoop mainRunLoop] addTimer:self.activationDelayTimer forMode:NSRunLoopCommonModes];
  201. }
  202. - (void)activationDelayTimerFired {
  203. if (self.networkActivityOccurring) {
  204. [self setCurrentState:AFNetworkActivityManagerStateActive];
  205. } else {
  206. [self setCurrentState:AFNetworkActivityManagerStateNotActive];
  207. }
  208. }
  209. - (void)startCompletionDelayTimer {
  210. [self.completionDelayTimer invalidate];
  211. self.completionDelayTimer = [NSTimer timerWithTimeInterval:self.completionDelay target:self selector:@selector(completionDelayTimerFired) userInfo:nil repeats:NO];
  212. [[NSRunLoop mainRunLoop] addTimer:self.completionDelayTimer forMode:NSRunLoopCommonModes];
  213. }
  214. - (void)completionDelayTimerFired {
  215. [self setCurrentState:AFNetworkActivityManagerStateNotActive];
  216. }
  217. - (void)cancelActivationDelayTimer {
  218. [self.activationDelayTimer invalidate];
  219. }
  220. - (void)cancelCompletionDelayTimer {
  221. [self.completionDelayTimer invalidate];
  222. }
  223. @end
  224. #endif