Add one feature, to allow user to limit the progress interval and reduce the frequency of progress callback
Also fix that progressive decoding should stop when all image data is downloaded
This commit is contained in:
parent
1c89282b08
commit
67e0df75c6
|
@ -200,11 +200,19 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext;
|
||||||
}
|
}
|
||||||
NSOperation<SDWebImageDownloaderOperation> *operation = [[operationClass alloc] initWithRequest:request inSession:sself.session options:options context:context];
|
NSOperation<SDWebImageDownloaderOperation> *operation = [[operationClass alloc] initWithRequest:request inSession:sself.session options:options context:context];
|
||||||
|
|
||||||
|
if ([operation respondsToSelector:@selector(setCredential:)]) {
|
||||||
if (sself.config.urlCredential) {
|
if (sself.config.urlCredential) {
|
||||||
operation.credential = sself.config.urlCredential;
|
operation.credential = sself.config.urlCredential;
|
||||||
} else if (sself.config.username && sself.config.password) {
|
} else if (sself.config.username && sself.config.password) {
|
||||||
operation.credential = [NSURLCredential credentialWithUser:sself.config.username password:sself.config.password persistence:NSURLCredentialPersistenceForSession];
|
operation.credential = [NSURLCredential credentialWithUser:sself.config.username password:sself.config.password persistence:NSURLCredentialPersistenceForSession];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([operation respondsToSelector:@selector(setMinimumProgressInterval:)]) {
|
||||||
|
NSTimeInterval minimumProgressInterval = sself.config.minimumProgressInterval;
|
||||||
|
minimumProgressInterval = MIN(MAX(minimumProgressInterval, 0), 1);
|
||||||
|
operation.minimumProgressInterval = minimumProgressInterval;
|
||||||
|
}
|
||||||
|
|
||||||
if (options & SDWebImageDownloaderHighPriority) {
|
if (options & SDWebImageDownloaderHighPriority) {
|
||||||
operation.queuePriority = NSOperationQueuePriorityHigh;
|
operation.queuePriority = NSOperationQueuePriorityHigh;
|
||||||
|
|
|
@ -41,6 +41,15 @@ typedef NS_ENUM(NSInteger, SDWebImageDownloaderExecutionOrder) {
|
||||||
*/
|
*/
|
||||||
@property (nonatomic, assign) NSTimeInterval downloadTimeout;
|
@property (nonatomic, assign) NSTimeInterval downloadTimeout;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The minimum interval about progress percent during network downloading. Which means the next progress callback and current progress callback's progress percent difference should be larger or equal to this value.
|
||||||
|
* The value should be 0.0-1.0.
|
||||||
|
* @note If you're using progressive decoding feature, this will also effect the image refresh rate.
|
||||||
|
* @note This value may enhance the performance if you don't want progress callback too frequently.
|
||||||
|
* Defaults to 0, which means each time we receive the new data from URLSession, we callback the progressBlock immediately.
|
||||||
|
*/
|
||||||
|
@property (nonatomic, assign) NSTimeInterval minimumProgressInterval;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The custom session configuration in use by NSURLSession. If you don't provide one, we will use `defaultSessionConfiguration` instead.
|
* The custom session configuration in use by NSURLSession. If you don't provide one, we will use `defaultSessionConfiguration` instead.
|
||||||
* Defatuls to nil.
|
* Defatuls to nil.
|
||||||
|
|
|
@ -34,6 +34,7 @@ static SDWebImageDownloaderConfig * _defaultDownloaderConfig;
|
||||||
SDWebImageDownloaderConfig *config = [[[self class] allocWithZone:zone] init];
|
SDWebImageDownloaderConfig *config = [[[self class] allocWithZone:zone] init];
|
||||||
config.maxConcurrentDownloads = self.maxConcurrentDownloads;
|
config.maxConcurrentDownloads = self.maxConcurrentDownloads;
|
||||||
config.downloadTimeout = self.downloadTimeout;
|
config.downloadTimeout = self.downloadTimeout;
|
||||||
|
config.minimumProgressInterval = self.minimumProgressInterval;
|
||||||
config.sessionConfiguration = [self.sessionConfiguration copyWithZone:zone];
|
config.sessionConfiguration = [self.sessionConfiguration copyWithZone:zone];
|
||||||
config.operationClass = self.operationClass;
|
config.operationClass = self.operationClass;
|
||||||
config.executionOrder = self.executionOrder;
|
config.executionOrder = self.executionOrder;
|
||||||
|
|
|
@ -36,9 +36,6 @@ FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadFinishNotification
|
||||||
- (nullable id)addHandlersForProgress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
|
- (nullable id)addHandlersForProgress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
|
||||||
completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock;
|
completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock;
|
||||||
|
|
||||||
- (nullable NSURLCredential *)credential;
|
|
||||||
- (void)setCredential:(nullable NSURLCredential *)value;
|
|
||||||
|
|
||||||
- (BOOL)cancel:(nullable id)token;
|
- (BOOL)cancel:(nullable id)token;
|
||||||
|
|
||||||
- (nullable NSURLRequest *)request;
|
- (nullable NSURLRequest *)request;
|
||||||
|
@ -46,6 +43,10 @@ FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadFinishNotification
|
||||||
|
|
||||||
@optional
|
@optional
|
||||||
- (nullable NSURLSessionTask *)dataTask;
|
- (nullable NSURLSessionTask *)dataTask;
|
||||||
|
- (nullable NSURLCredential *)credential;
|
||||||
|
- (void)setCredential:(nullable NSURLCredential *)credential;
|
||||||
|
- (NSTimeInterval)minimumProgressInterval;
|
||||||
|
- (void)setMinimumProgressInterval:(NSTimeInterval)minimumProgressInterval;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@ -74,6 +75,15 @@ FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadFinishNotification
|
||||||
*/
|
*/
|
||||||
@property (nonatomic, strong, nullable) NSURLCredential *credential;
|
@property (nonatomic, strong, nullable) NSURLCredential *credential;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The minimum interval about progress percent during network downloading. Which means the next progress callback and current progress callback's progress percent difference should be larger or equal to this value.
|
||||||
|
* The value should be 0.0-1.0.
|
||||||
|
* @note If you're using progressive decoding feature, this will also effect the image refresh rate.
|
||||||
|
* @note This value may enhance the performance if you don't want progress callback too frequently.
|
||||||
|
* Defaults to 0, which means each time we receive the new data from URLSession, we callback the progressBlock immediately.
|
||||||
|
*/
|
||||||
|
@property (assign, nonatomic) NSTimeInterval minimumProgressInterval;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The options for the receiver.
|
* The options for the receiver.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -37,9 +37,11 @@ typedef NSMutableDictionary<NSString *, id> SDCallbacksDictionary;
|
||||||
@property (assign, nonatomic, getter = isFinished) BOOL finished;
|
@property (assign, nonatomic, getter = isFinished) BOOL finished;
|
||||||
@property (strong, nonatomic, nullable) NSMutableData *imageData;
|
@property (strong, nonatomic, nullable) NSMutableData *imageData;
|
||||||
@property (copy, nonatomic, nullable) NSData *cachedData; // for `SDWebImageDownloaderIgnoreCachedResponse`
|
@property (copy, nonatomic, nullable) NSData *cachedData; // for `SDWebImageDownloaderIgnoreCachedResponse`
|
||||||
@property (assign, nonatomic, readwrite) NSUInteger expectedSize;
|
@property (assign, nonatomic) NSUInteger expectedSize; // may be 0
|
||||||
|
@property (assign, nonatomic) NSUInteger receivedSize;
|
||||||
@property (strong, nonatomic, nullable, readwrite) NSURLResponse *response;
|
@property (strong, nonatomic, nullable, readwrite) NSURLResponse *response;
|
||||||
@property (strong, nonatomic, nullable) NSError *responseError;
|
@property (strong, nonatomic, nullable) NSError *responseError;
|
||||||
|
@property (assign, nonatomic) double previousProgress; // previous progress percent
|
||||||
|
|
||||||
// This is weak because it is injected by whoever manages this session. If this gets nil-ed out, we won't be able to run
|
// This is weak because it is injected by whoever manages this session. If this gets nil-ed out, we won't be able to run
|
||||||
// the task associated with this operation
|
// the task associated with this operation
|
||||||
|
@ -332,16 +334,36 @@ didReceiveResponse:(NSURLResponse *)response
|
||||||
}
|
}
|
||||||
[self.imageData appendData:data];
|
[self.imageData appendData:data];
|
||||||
|
|
||||||
if ((self.options & SDWebImageDownloaderProgressiveLoad) && self.expectedSize > 0) {
|
self.receivedSize = self.imageData.length;
|
||||||
|
if (self.expectedSize == 0) {
|
||||||
|
// Unknown expectedSize, immediately call progressBlock and return
|
||||||
|
for (SDWebImageDownloaderProgressBlock progressBlock in [self callbacksForKey:kProgressCallbackKey]) {
|
||||||
|
progressBlock(self.receivedSize, self.expectedSize, self.request.URL);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the finish status
|
||||||
|
BOOL finished = (self.receivedSize >= self.expectedSize);
|
||||||
|
// Get the current progress
|
||||||
|
double currentProgress = (double)self.receivedSize / (double)self.expectedSize;
|
||||||
|
double previousProgress = self.previousProgress;
|
||||||
|
// Check if we need callback progress
|
||||||
|
if (currentProgress - previousProgress < self.minimumProgressInterval) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.previousProgress = currentProgress;
|
||||||
|
|
||||||
|
if (self.options & SDWebImageDownloaderProgressiveLoad) {
|
||||||
// Get the image data
|
// Get the image data
|
||||||
NSData *imageData = [self.imageData copy];
|
NSData *imageData = [self.imageData copy];
|
||||||
// Get the total bytes downloaded
|
|
||||||
const NSUInteger totalSize = imageData.length;
|
|
||||||
// Get the finish status
|
|
||||||
BOOL finished = (totalSize >= self.expectedSize);
|
|
||||||
|
|
||||||
// progressive decode the image in coder queue
|
// progressive decode the image in coder queue
|
||||||
dispatch_async(self.coderQueue, ^{
|
dispatch_async(self.coderQueue, ^{
|
||||||
|
// If all the data has already been downloaded, earily return to avoid further decoding
|
||||||
|
if (self.receivedSize >= self.expectedSize) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
UIImage *image = SDImageLoaderDecodeProgressiveImageData(imageData, self.request.URL, finished, self, [[self class] imageOptionsFromDownloaderOptions:self.options], self.context);
|
UIImage *image = SDImageLoaderDecodeProgressiveImageData(imageData, self.request.URL, finished, self, [[self class] imageOptionsFromDownloaderOptions:self.options], self.context);
|
||||||
if (image) {
|
if (image) {
|
||||||
// We do not keep the progressive decoding image even when `finished`=YES. Because they are for view rendering but not take full function from downloader options. And some coders implementation may not keep consistent between progressive decoding and normal decoding.
|
// We do not keep the progressive decoding image even when `finished`=YES. Because they are for view rendering but not take full function from downloader options. And some coders implementation may not keep consistent between progressive decoding and normal decoding.
|
||||||
|
@ -352,7 +374,7 @@ didReceiveResponse:(NSURLResponse *)response
|
||||||
}
|
}
|
||||||
|
|
||||||
for (SDWebImageDownloaderProgressBlock progressBlock in [self callbacksForKey:kProgressCallbackKey]) {
|
for (SDWebImageDownloaderProgressBlock progressBlock in [self callbacksForKey:kProgressCallbackKey]) {
|
||||||
progressBlock(self.imageData.length, self.expectedSize, self.request.URL);
|
progressBlock(self.receivedSize, self.expectedSize, self.request.URL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue