//
|
// YYWebImageManager.m
|
// YYWebImage <https://github.com/ibireme/YYWebImage>
|
//
|
// Created by ibireme on 15/2/19.
|
// Copyright (c) 2015 ibireme.
|
//
|
// This source code is licensed under the MIT-style license found in the
|
// LICENSE file in the root directory of this source tree.
|
//
|
|
#import "YYWebImageManager.h"
|
#import "YYImageCache.h"
|
#import "YYWebImageOperation.h"
|
#import "YYImageCoder.h"
|
#import <objc/runtime.h>
|
|
#define kNetworkIndicatorDelay (1/30.0)
|
|
|
/// Returns nil in App Extension.
|
static UIApplication *_YYSharedApplication() {
|
static BOOL isAppExtension = NO;
|
static dispatch_once_t onceToken;
|
dispatch_once(&onceToken, ^{
|
Class cls = NSClassFromString(@"UIApplication");
|
if(!cls || ![cls respondsToSelector:@selector(sharedApplication)]) isAppExtension = YES;
|
if ([[[NSBundle mainBundle] bundlePath] hasSuffix:@".appex"]) isAppExtension = YES;
|
});
|
#pragma clang diagnostic push
|
#pragma clang diagnostic ignored "-Wundeclared-selector"
|
return isAppExtension ? nil : [UIApplication performSelector:@selector(sharedApplication)];
|
#pragma clang diagnostic pop
|
}
|
|
|
@interface _YYWebImageApplicationNetworkIndicatorInfo : NSObject
|
@property (nonatomic, assign) NSInteger count;
|
@property (nonatomic, strong) NSTimer *timer;
|
@end
|
@implementation _YYWebImageApplicationNetworkIndicatorInfo
|
@end
|
|
@implementation YYWebImageManager
|
|
+ (instancetype)sharedManager {
|
static YYWebImageManager *manager;
|
static dispatch_once_t onceToken;
|
dispatch_once(&onceToken, ^{
|
YYImageCache *cache = [YYImageCache sharedCache];
|
NSOperationQueue *queue = [NSOperationQueue new];
|
if ([queue respondsToSelector:@selector(setQualityOfService:)]) {
|
queue.qualityOfService = NSQualityOfServiceBackground;
|
}
|
manager = [[self alloc] initWithCache:cache queue:queue];
|
});
|
return manager;
|
}
|
|
- (instancetype)init {
|
@throw [NSException exceptionWithName:@"YYWebImageManager init error" reason:@"Use the designated initializer to init." userInfo:nil];
|
return [self initWithCache:nil queue:nil];
|
}
|
|
- (instancetype)initWithCache:(YYImageCache *)cache queue:(NSOperationQueue *)queue{
|
self = [super init];
|
if (!self) return nil;
|
_cache = cache;
|
_queue = queue;
|
_timeout = 15.0;
|
if (YYImageWebPAvailable()) {
|
_headers = @{ @"Accept" : @"image/webp,image/*;q=0.8" };
|
} else {
|
_headers = @{ @"Accept" : @"image/*;q=0.8" };
|
}
|
return self;
|
}
|
|
- (YYWebImageOperation *)requestImageWithURL:(NSURL *)url
|
options:(YYWebImageOptions)options
|
progress:(YYWebImageProgressBlock)progress
|
transform:(YYWebImageTransformBlock)transform
|
completion:(YYWebImageCompletionBlock)completion {
|
|
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
|
request.timeoutInterval = _timeout;
|
request.HTTPShouldHandleCookies = (options & YYWebImageOptionHandleCookies) != 0;
|
request.allHTTPHeaderFields = [self headersForURL:url];
|
request.HTTPShouldUsePipelining = YES;
|
request.cachePolicy = (options & YYWebImageOptionUseNSURLCache) ?
|
NSURLRequestUseProtocolCachePolicy : NSURLRequestReloadIgnoringLocalCacheData;
|
|
YYWebImageOperation *operation = [[YYWebImageOperation alloc] initWithRequest:request
|
options:options
|
cache:_cache
|
cacheKey:[self cacheKeyForURL:url]
|
progress:progress
|
transform:transform ? transform : _sharedTransformBlock
|
completion:completion];
|
|
if (_username && _password) {
|
operation.credential = [NSURLCredential credentialWithUser:_username password:_password persistence:NSURLCredentialPersistenceForSession];
|
}
|
if (operation) {
|
NSOperationQueue *queue = _queue;
|
if (queue) {
|
[queue addOperation:operation];
|
} else {
|
[operation start];
|
}
|
}
|
return operation;
|
}
|
|
- (NSDictionary *)headersForURL:(NSURL *)url {
|
if (!url) return nil;
|
return _headersFilter ? _headersFilter(url, _headers) : _headers;
|
}
|
|
- (NSString *)cacheKeyForURL:(NSURL *)url {
|
if (!url) return nil;
|
return _cacheKeyFilter ? _cacheKeyFilter(url) : url.absoluteString;
|
}
|
|
|
|
#pragma mark Network Indicator
|
|
+ (_YYWebImageApplicationNetworkIndicatorInfo *)_networkIndicatorInfo {
|
return objc_getAssociatedObject(self, @selector(_networkIndicatorInfo));
|
}
|
|
+ (void)_setNetworkIndicatorInfo:(_YYWebImageApplicationNetworkIndicatorInfo *)info {
|
objc_setAssociatedObject(self, @selector(_networkIndicatorInfo), info, OBJC_ASSOCIATION_RETAIN);
|
}
|
|
+ (void)_delaySetActivity:(NSTimer *)timer {
|
UIApplication *app = _YYSharedApplication();
|
if (!app) return;
|
|
NSNumber *visiable = timer.userInfo;
|
if (app.networkActivityIndicatorVisible != visiable.boolValue) {
|
[app setNetworkActivityIndicatorVisible:visiable.boolValue];
|
}
|
[timer invalidate];
|
}
|
|
+ (void)_changeNetworkActivityCount:(NSInteger)delta {
|
if (!_YYSharedApplication()) return;
|
|
void (^block)() = ^{
|
_YYWebImageApplicationNetworkIndicatorInfo *info = [self _networkIndicatorInfo];
|
if (!info) {
|
info = [_YYWebImageApplicationNetworkIndicatorInfo new];
|
[self _setNetworkIndicatorInfo:info];
|
}
|
NSInteger count = info.count;
|
count += delta;
|
info.count = count;
|
[info.timer invalidate];
|
info.timer = [NSTimer timerWithTimeInterval:kNetworkIndicatorDelay target:self selector:@selector(_delaySetActivity:) userInfo:@(info.count > 0) repeats:NO];
|
[[NSRunLoop mainRunLoop] addTimer:info.timer forMode:NSRunLoopCommonModes];
|
};
|
if ([NSThread isMainThread]) {
|
block();
|
} else {
|
dispatch_async(dispatch_get_main_queue(), block);
|
}
|
}
|
|
+ (void)incrementNetworkActivityCount {
|
[self _changeNetworkActivityCount:1];
|
}
|
|
+ (void)decrementNetworkActivityCount {
|
[self _changeNetworkActivityCount:-1];
|
}
|
|
+ (NSInteger)currentNetworkActivityCount {
|
_YYWebImageApplicationNetworkIndicatorInfo *info = [self _networkIndicatorInfo];
|
return info.count;
|
}
|
|
@end
|