EMASCurlWeb/EMASCurlWebNetworkManager.m (113 lines of code) (raw):

// // EMASCurlNetworkSession.m // #import "EMASCurlWebNetworkManager.h" #import "EMASCurlWebRequestExecutor.h" #import "EMASCurlWebUtils.h" #import "EMASCurlWebURLResponseCache.h" #import <os/lock.h> @interface EMASCurlWebNetworkManager () @property (nonatomic, strong) EMASCurlSafeArray<EMASCurlNetworkDataTask *> *dataTasks; @property (nonatomic, assign) NSUInteger currentCacheItemCount; @property (nonatomic, assign) NSUInteger currentCacheCapacity; @property (nonatomic, strong) EMASCurlWebRequestExecutor *networkManager; @property (nonatomic, strong) EMASCurlWebURLResponseCache *httpResponseCache; @end @implementation EMASCurlWebNetworkManager { os_unfair_lock _dataTasksLock; } - (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)sessionConfiguration { self = [super init]; if (self) { _dataTasksLock = OS_UNFAIR_LOCK_INIT; _dataTasks = [EMASCurlSafeArray new]; _currentCacheCapacity = 0; _currentCacheItemCount = 0; _networkManager = [[EMASCurlWebRequestExecutor alloc] initWithSessionConfiguration:sessionConfiguration]; _httpResponseCache = [[EMASCurlWebURLResponseCache alloc] init]; } return self; } - (nullable EMASCurlNetworkDataTask *)dataTaskWithRequest:(NSURLRequest *)request responseCallback:(EMASCurlNetResponseCallback)responseCallback dataCallback:(EMASCurlNetDataCallback)dataCallback successCallback:(EMASCurlNetSuccessCallback)successCallback failCallback:(EMASCurlNetFailCallback)failCallback redirectCallback:(EMASCurlNetRedirectCallback)redirectCallback { EMASCurlNetworkDataTask *dataTask = [[EMASCurlNetworkDataTask alloc] initWithRequest:request]; dataTask.responseCallback = responseCallback; dataTask.dataCallback = dataCallback; dataTask.redirectCallback = redirectCallback; dataTask.networkManagerWeakRef = self.networkManager; dataTask.httpCacheWeakRef = self.httpResponseCache; EMASCurlWeak(self) EMASCurlWeak(dataTask) dataTask.retryHandler = ^{ EMASCurlStrong(self) EMASCurlStrong(dataTask) EMASCurlNetworkDataTask *retryTask = [self dataTaskWithRequest:dataTask.originalRequest responseCallback:dataTask.responseCallback dataCallback:dataTask.dataCallback successCallback:dataTask.successCallback failCallback:dataTask.failCallback redirectCallback:dataTask.redirectCallback]; if (!retryTask) { return; } retryTask.currentRetryCount = dataTask.currentRetryCount; [retryTask resume]; }; dataTask.cancelHandler = ^{ EMASCurlStrong(self) EMASCurlStrong(dataTask) [self cancelTask:dataTask]; }; dataTask.successCallback = ^{ EMASCurlStrong(dataTask) EMASCurlStrong(self) if (!self || !dataTask) return; if (successCallback) { successCallback(); } [self removeDataTask:dataTask]; }; dataTask.failCallback = ^(NSError * _Nonnull error) { EMASCurlStrong(dataTask) EMASCurlStrong(self) if (!self || !dataTask) return; if (failCallback) { failCallback(error); } [self removeDataTask:dataTask]; }; // 根据请求方法判断是否允许缓存 BOOL isNonGET = ![[request.HTTPMethod uppercaseString] isEqualToString:@"GET"]; NSString *mainDocumentURL = request.mainDocumentURL.absoluteString; NSString *requestURL = request.URL.absoluteString; BOOL isMainURLMatch = ([EMASCurlWebUtils isValidStr:mainDocumentURL] && [EMASCurlWebUtils isEqualURLA:requestURL withURLB:mainDocumentURL]); if (isNonGET || isMainURLMatch) { dataTask.canCache = NO; } else { dataTask.canCache = YES; } os_unfair_lock_lock(&_dataTasksLock); [self.dataTasks addObject:dataTask]; os_unfair_lock_unlock(&_dataTasksLock); return dataTask; } // 取消指定任务 - (void)cancelTask:(EMASCurlNetworkDataTask *)task { [task cancel]; [self removeDataTask:task]; } // 取消所有任务 - (void)cancelAllTasks { os_unfair_lock_lock(&_dataTasksLock); NSArray<EMASCurlNetworkDataTask *> *tasksCopy = [self.dataTasks copy]; os_unfair_lock_unlock(&_dataTasksLock); for (EMASCurlNetworkDataTask *task in tasksCopy) { [task cancel]; [self removeDataTask:task]; } } // 从任务列表中移除 - (void)removeDataTask:(EMASCurlNetworkDataTask *)task { os_unfair_lock_lock(&_dataTasksLock); [self.dataTasks removeObject:task]; os_unfair_lock_unlock(&_dataTasksLock); } @end