添加网络库,修改问题
This commit is contained in:
@@ -0,0 +1,421 @@
|
||||
// AFImageDownloader.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 <TargetConditionals.h>
|
||||
|
||||
#if TARGET_OS_IOS || TARGET_OS_TV
|
||||
|
||||
#import "AFImageDownloader.h"
|
||||
#import "AFHTTPSessionManager.h"
|
||||
|
||||
@interface AFImageDownloaderResponseHandler : NSObject
|
||||
@property (nonatomic, strong) NSUUID *uuid;
|
||||
@property (nonatomic, copy) void (^successBlock)(NSURLRequest *, NSHTTPURLResponse *, UIImage *);
|
||||
@property (nonatomic, copy) void (^failureBlock)(NSURLRequest *, NSHTTPURLResponse *, NSError *);
|
||||
@end
|
||||
|
||||
@implementation AFImageDownloaderResponseHandler
|
||||
|
||||
- (instancetype)initWithUUID:(NSUUID *)uuid
|
||||
success:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, UIImage *responseObject))success
|
||||
failure:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, NSError *error))failure {
|
||||
if (self = [self init]) {
|
||||
self.uuid = uuid;
|
||||
self.successBlock = success;
|
||||
self.failureBlock = failure;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSString *)description {
|
||||
return [NSString stringWithFormat: @"<AFImageDownloaderResponseHandler>UUID: %@", [self.uuid UUIDString]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface AFImageDownloaderMergedTask : NSObject
|
||||
@property (nonatomic, strong) NSString *URLIdentifier;
|
||||
@property (nonatomic, strong) NSUUID *identifier;
|
||||
@property (nonatomic, strong) NSURLSessionDataTask *task;
|
||||
@property (nonatomic, strong) NSMutableArray <AFImageDownloaderResponseHandler*> *responseHandlers;
|
||||
|
||||
@end
|
||||
|
||||
@implementation AFImageDownloaderMergedTask
|
||||
|
||||
- (instancetype)initWithURLIdentifier:(NSString *)URLIdentifier identifier:(NSUUID *)identifier task:(NSURLSessionDataTask *)task {
|
||||
if (self = [self init]) {
|
||||
self.URLIdentifier = URLIdentifier;
|
||||
self.task = task;
|
||||
self.identifier = identifier;
|
||||
self.responseHandlers = [[NSMutableArray alloc] init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)addResponseHandler:(AFImageDownloaderResponseHandler *)handler {
|
||||
[self.responseHandlers addObject:handler];
|
||||
}
|
||||
|
||||
- (void)removeResponseHandler:(AFImageDownloaderResponseHandler *)handler {
|
||||
[self.responseHandlers removeObject:handler];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation AFImageDownloadReceipt
|
||||
|
||||
- (instancetype)initWithReceiptID:(NSUUID *)receiptID task:(NSURLSessionDataTask *)task {
|
||||
if (self = [self init]) {
|
||||
self.receiptID = receiptID;
|
||||
self.task = task;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface AFImageDownloader ()
|
||||
|
||||
@property (nonatomic, strong) dispatch_queue_t synchronizationQueue;
|
||||
@property (nonatomic, strong) dispatch_queue_t responseQueue;
|
||||
|
||||
@property (nonatomic, assign) NSInteger maximumActiveDownloads;
|
||||
@property (nonatomic, assign) NSInteger activeRequestCount;
|
||||
|
||||
@property (nonatomic, strong) NSMutableArray *queuedMergedTasks;
|
||||
@property (nonatomic, strong) NSMutableDictionary *mergedTasks;
|
||||
|
||||
@end
|
||||
|
||||
@implementation AFImageDownloader
|
||||
|
||||
+ (NSURLCache *)defaultURLCache {
|
||||
NSUInteger memoryCapacity = 20 * 1024 * 1024; // 20MB
|
||||
NSUInteger diskCapacity = 150 * 1024 * 1024; // 150MB
|
||||
NSURL *cacheURL = [[[NSFileManager defaultManager] URLForDirectory:NSCachesDirectory
|
||||
inDomain:NSUserDomainMask
|
||||
appropriateForURL:nil
|
||||
create:YES
|
||||
error:nil]
|
||||
URLByAppendingPathComponent:@"com.alamofire.imagedownloader"];
|
||||
|
||||
#if TARGET_OS_MACCATALYST
|
||||
return [[NSURLCache alloc] initWithMemoryCapacity:memoryCapacity
|
||||
diskCapacity:diskCapacity
|
||||
directoryURL:cacheURL];
|
||||
#else
|
||||
return [[NSURLCache alloc] initWithMemoryCapacity:memoryCapacity
|
||||
diskCapacity:diskCapacity
|
||||
diskPath:[cacheURL path]];
|
||||
#endif
|
||||
}
|
||||
|
||||
+ (NSURLSessionConfiguration *)defaultURLSessionConfiguration {
|
||||
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
|
||||
|
||||
//TODO set the default HTTP headers
|
||||
|
||||
configuration.HTTPShouldSetCookies = YES;
|
||||
configuration.HTTPShouldUsePipelining = NO;
|
||||
|
||||
configuration.requestCachePolicy = NSURLRequestUseProtocolCachePolicy;
|
||||
configuration.allowsCellularAccess = YES;
|
||||
configuration.timeoutIntervalForRequest = 60.0;
|
||||
configuration.URLCache = [AFImageDownloader defaultURLCache];
|
||||
|
||||
return configuration;
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
NSURLSessionConfiguration *defaultConfiguration = [self.class defaultURLSessionConfiguration];
|
||||
return [self initWithSessionConfiguration:defaultConfiguration];
|
||||
}
|
||||
|
||||
- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration {
|
||||
AFHTTPSessionManager *sessionManager = [[AFHTTPSessionManager alloc] initWithSessionConfiguration:configuration];
|
||||
sessionManager.responseSerializer = [AFImageResponseSerializer serializer];
|
||||
|
||||
return [self initWithSessionManager:sessionManager
|
||||
downloadPrioritization:AFImageDownloadPrioritizationFIFO
|
||||
maximumActiveDownloads:4
|
||||
imageCache:[[AFAutoPurgingImageCache alloc] init]];
|
||||
}
|
||||
|
||||
- (instancetype)initWithSessionManager:(AFHTTPSessionManager *)sessionManager
|
||||
downloadPrioritization:(AFImageDownloadPrioritization)downloadPrioritization
|
||||
maximumActiveDownloads:(NSInteger)maximumActiveDownloads
|
||||
imageCache:(id <AFImageRequestCache>)imageCache {
|
||||
if (self = [super init]) {
|
||||
self.sessionManager = sessionManager;
|
||||
|
||||
self.downloadPrioritization = downloadPrioritization;
|
||||
self.maximumActiveDownloads = maximumActiveDownloads;
|
||||
self.imageCache = imageCache;
|
||||
|
||||
self.queuedMergedTasks = [[NSMutableArray alloc] init];
|
||||
self.mergedTasks = [[NSMutableDictionary alloc] init];
|
||||
self.activeRequestCount = 0;
|
||||
|
||||
NSString *name = [NSString stringWithFormat:@"com.alamofire.imagedownloader.synchronizationqueue-%@", [[NSUUID UUID] UUIDString]];
|
||||
self.synchronizationQueue = dispatch_queue_create([name cStringUsingEncoding:NSASCIIStringEncoding], DISPATCH_QUEUE_SERIAL);
|
||||
|
||||
name = [NSString stringWithFormat:@"com.alamofire.imagedownloader.responsequeue-%@", [[NSUUID UUID] UUIDString]];
|
||||
self.responseQueue = dispatch_queue_create([name cStringUsingEncoding:NSASCIIStringEncoding], DISPATCH_QUEUE_CONCURRENT);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (instancetype)defaultInstance {
|
||||
static AFImageDownloader *sharedInstance = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
sharedInstance = [[self alloc] init];
|
||||
});
|
||||
return sharedInstance;
|
||||
}
|
||||
|
||||
- (nullable AFImageDownloadReceipt *)downloadImageForURLRequest:(NSURLRequest *)request
|
||||
success:(void (^)(NSURLRequest * _Nonnull, NSHTTPURLResponse * _Nullable, UIImage * _Nonnull))success
|
||||
failure:(void (^)(NSURLRequest * _Nonnull, NSHTTPURLResponse * _Nullable, NSError * _Nonnull))failure {
|
||||
return [self downloadImageForURLRequest:request withReceiptID:[NSUUID UUID] success:success failure:failure];
|
||||
}
|
||||
|
||||
- (nullable AFImageDownloadReceipt *)downloadImageForURLRequest:(NSURLRequest *)request
|
||||
withReceiptID:(nonnull NSUUID *)receiptID
|
||||
success:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, UIImage *responseObject))success
|
||||
failure:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, NSError *error))failure {
|
||||
__block NSURLSessionDataTask *task = nil;
|
||||
dispatch_sync(self.synchronizationQueue, ^{
|
||||
NSString *URLIdentifier = request.URL.absoluteString;
|
||||
if (URLIdentifier == nil) {
|
||||
if (failure) {
|
||||
NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorBadURL userInfo:nil];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
failure(request, nil, error);
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 1) Append the success and failure blocks to a pre-existing request if it already exists
|
||||
AFImageDownloaderMergedTask *existingMergedTask = self.mergedTasks[URLIdentifier];
|
||||
if (existingMergedTask != nil) {
|
||||
AFImageDownloaderResponseHandler *handler = [[AFImageDownloaderResponseHandler alloc] initWithUUID:receiptID success:success failure:failure];
|
||||
[existingMergedTask addResponseHandler:handler];
|
||||
task = existingMergedTask.task;
|
||||
return;
|
||||
}
|
||||
|
||||
// 2) Attempt to load the image from the image cache if the cache policy allows it
|
||||
switch (request.cachePolicy) {
|
||||
case NSURLRequestUseProtocolCachePolicy:
|
||||
case NSURLRequestReturnCacheDataElseLoad:
|
||||
case NSURLRequestReturnCacheDataDontLoad: {
|
||||
UIImage *cachedImage = [self.imageCache imageforRequest:request withAdditionalIdentifier:nil];
|
||||
if (cachedImage != nil) {
|
||||
if (success) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
success(request, nil, cachedImage);
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// 3) Create the request and set up authentication, validation and response serialization
|
||||
NSUUID *mergedTaskIdentifier = [NSUUID UUID];
|
||||
NSURLSessionDataTask *createdTask;
|
||||
__weak __typeof__(self) weakSelf = self;
|
||||
|
||||
createdTask = [self.sessionManager
|
||||
dataTaskWithRequest:request
|
||||
uploadProgress:nil
|
||||
downloadProgress:nil
|
||||
completionHandler:^(NSURLResponse * _Nonnull response, id _Nullable responseObject, NSError * _Nullable error) {
|
||||
dispatch_async(self.responseQueue, ^{
|
||||
__strong __typeof__(weakSelf) strongSelf = weakSelf;
|
||||
AFImageDownloaderMergedTask *mergedTask = [strongSelf safelyGetMergedTask:URLIdentifier];
|
||||
if ([mergedTask.identifier isEqual:mergedTaskIdentifier]) {
|
||||
mergedTask = [strongSelf safelyRemoveMergedTaskWithURLIdentifier:URLIdentifier];
|
||||
if (error) {
|
||||
for (AFImageDownloaderResponseHandler *handler in mergedTask.responseHandlers) {
|
||||
if (handler.failureBlock) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
handler.failureBlock(request, (NSHTTPURLResponse *)response, error);
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ([strongSelf.imageCache shouldCacheImage:responseObject forRequest:request withAdditionalIdentifier:nil]) {
|
||||
[strongSelf.imageCache addImage:responseObject forRequest:request withAdditionalIdentifier:nil];
|
||||
}
|
||||
|
||||
for (AFImageDownloaderResponseHandler *handler in mergedTask.responseHandlers) {
|
||||
if (handler.successBlock) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
handler.successBlock(request, (NSHTTPURLResponse *)response, responseObject);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
[strongSelf safelyDecrementActiveTaskCount];
|
||||
[strongSelf safelyStartNextTaskIfNecessary];
|
||||
});
|
||||
}];
|
||||
|
||||
// 4) Store the response handler for use when the request completes
|
||||
AFImageDownloaderResponseHandler *handler = [[AFImageDownloaderResponseHandler alloc] initWithUUID:receiptID
|
||||
success:success
|
||||
failure:failure];
|
||||
AFImageDownloaderMergedTask *mergedTask = [[AFImageDownloaderMergedTask alloc]
|
||||
initWithURLIdentifier:URLIdentifier
|
||||
identifier:mergedTaskIdentifier
|
||||
task:createdTask];
|
||||
[mergedTask addResponseHandler:handler];
|
||||
self.mergedTasks[URLIdentifier] = mergedTask;
|
||||
|
||||
// 5) Either start the request or enqueue it depending on the current active request count
|
||||
if ([self isActiveRequestCountBelowMaximumLimit]) {
|
||||
[self startMergedTask:mergedTask];
|
||||
} else {
|
||||
[self enqueueMergedTask:mergedTask];
|
||||
}
|
||||
|
||||
task = mergedTask.task;
|
||||
});
|
||||
if (task) {
|
||||
return [[AFImageDownloadReceipt alloc] initWithReceiptID:receiptID task:task];
|
||||
} else {
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)cancelTaskForImageDownloadReceipt:(AFImageDownloadReceipt *)imageDownloadReceipt {
|
||||
dispatch_sync(self.synchronizationQueue, ^{
|
||||
NSString *URLIdentifier = imageDownloadReceipt.task.originalRequest.URL.absoluteString;
|
||||
AFImageDownloaderMergedTask *mergedTask = self.mergedTasks[URLIdentifier];
|
||||
NSUInteger index = [mergedTask.responseHandlers indexOfObjectPassingTest:^BOOL(AFImageDownloaderResponseHandler * _Nonnull handler, __unused NSUInteger idx, __unused BOOL * _Nonnull stop) {
|
||||
return handler.uuid == imageDownloadReceipt.receiptID;
|
||||
}];
|
||||
|
||||
if (index != NSNotFound) {
|
||||
AFImageDownloaderResponseHandler *handler = mergedTask.responseHandlers[index];
|
||||
[mergedTask removeResponseHandler:handler];
|
||||
NSString *failureReason = [NSString stringWithFormat:@"ImageDownloader cancelled URL request: %@",imageDownloadReceipt.task.originalRequest.URL.absoluteString];
|
||||
NSDictionary *userInfo = @{NSLocalizedFailureReasonErrorKey:failureReason};
|
||||
NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorCancelled userInfo:userInfo];
|
||||
if (handler.failureBlock) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
handler.failureBlock(imageDownloadReceipt.task.originalRequest, nil, error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (mergedTask.responseHandlers.count == 0) {
|
||||
[mergedTask.task cancel];
|
||||
[self removeMergedTaskWithURLIdentifier:URLIdentifier];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (AFImageDownloaderMergedTask *)safelyRemoveMergedTaskWithURLIdentifier:(NSString *)URLIdentifier {
|
||||
__block AFImageDownloaderMergedTask *mergedTask = nil;
|
||||
dispatch_sync(self.synchronizationQueue, ^{
|
||||
mergedTask = [self removeMergedTaskWithURLIdentifier:URLIdentifier];
|
||||
});
|
||||
return mergedTask;
|
||||
}
|
||||
|
||||
//This method should only be called from safely within the synchronizationQueue
|
||||
- (AFImageDownloaderMergedTask *)removeMergedTaskWithURLIdentifier:(NSString *)URLIdentifier {
|
||||
AFImageDownloaderMergedTask *mergedTask = self.mergedTasks[URLIdentifier];
|
||||
[self.mergedTasks removeObjectForKey:URLIdentifier];
|
||||
return mergedTask;
|
||||
}
|
||||
|
||||
- (void)safelyDecrementActiveTaskCount {
|
||||
dispatch_sync(self.synchronizationQueue, ^{
|
||||
if (self.activeRequestCount > 0) {
|
||||
self.activeRequestCount -= 1;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (void)safelyStartNextTaskIfNecessary {
|
||||
dispatch_sync(self.synchronizationQueue, ^{
|
||||
if ([self isActiveRequestCountBelowMaximumLimit]) {
|
||||
while (self.queuedMergedTasks.count > 0) {
|
||||
AFImageDownloaderMergedTask *mergedTask = [self dequeueMergedTask];
|
||||
if (mergedTask.task.state == NSURLSessionTaskStateSuspended) {
|
||||
[self startMergedTask:mergedTask];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (void)startMergedTask:(AFImageDownloaderMergedTask *)mergedTask {
|
||||
[mergedTask.task resume];
|
||||
++self.activeRequestCount;
|
||||
}
|
||||
|
||||
- (void)enqueueMergedTask:(AFImageDownloaderMergedTask *)mergedTask {
|
||||
switch (self.downloadPrioritization) {
|
||||
case AFImageDownloadPrioritizationFIFO:
|
||||
[self.queuedMergedTasks addObject:mergedTask];
|
||||
break;
|
||||
case AFImageDownloadPrioritizationLIFO:
|
||||
[self.queuedMergedTasks insertObject:mergedTask atIndex:0];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
- (AFImageDownloaderMergedTask *)dequeueMergedTask {
|
||||
AFImageDownloaderMergedTask *mergedTask = nil;
|
||||
mergedTask = [self.queuedMergedTasks firstObject];
|
||||
[self.queuedMergedTasks removeObject:mergedTask];
|
||||
return mergedTask;
|
||||
}
|
||||
|
||||
- (BOOL)isActiveRequestCountBelowMaximumLimit {
|
||||
return self.activeRequestCount < self.maximumActiveDownloads;
|
||||
}
|
||||
|
||||
- (AFImageDownloaderMergedTask *)safelyGetMergedTask:(NSString *)URLIdentifier {
|
||||
__block AFImageDownloaderMergedTask *mergedTask;
|
||||
dispatch_sync(self.synchronizationQueue, ^(){
|
||||
mergedTask = self.mergedTasks[URLIdentifier];
|
||||
});
|
||||
return mergedTask;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user