Merge pull request #2415 from dreampiggy/feature_minimum_progress_interval
Feature minimum progress interval
This commit is contained in:
commit
1d4823eb48
|
@ -250,10 +250,18 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext;
|
|||
}
|
||||
NSOperation<SDWebImageDownloaderOperation> *operation = [[operationClass alloc] initWithRequest:request inSession:self.session options:options context:context];
|
||||
|
||||
if (self.config.urlCredential) {
|
||||
operation.credential = self.config.urlCredential;
|
||||
} else if (self.config.username && self.config.password) {
|
||||
operation.credential = [NSURLCredential credentialWithUser:self.config.username password:self.config.password persistence:NSURLCredentialPersistenceForSession];
|
||||
if ([operation respondsToSelector:@selector(setCredential:)]) {
|
||||
if (self.config.urlCredential) {
|
||||
operation.credential = self.config.urlCredential;
|
||||
} else if (self.config.username && self.config.password) {
|
||||
operation.credential = [NSURLCredential credentialWithUser:self.config.username password:self.config.password persistence:NSURLCredentialPersistenceForSession];
|
||||
}
|
||||
}
|
||||
|
||||
if ([operation respondsToSelector:@selector(setMinimumProgressInterval:)]) {
|
||||
NSTimeInterval minimumProgressInterval = self.config.minimumProgressInterval;
|
||||
minimumProgressInterval = MIN(MAX(minimumProgressInterval, 0), 1);
|
||||
operation.minimumProgressInterval = minimumProgressInterval;
|
||||
}
|
||||
|
||||
if (options & SDWebImageDownloaderHighPriority) {
|
||||
|
|
|
@ -41,6 +41,15 @@ typedef NS_ENUM(NSInteger, SDWebImageDownloaderExecutionOrder) {
|
|||
*/
|
||||
@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.
|
||||
* Defatuls to nil.
|
||||
|
|
|
@ -34,6 +34,7 @@ static SDWebImageDownloaderConfig * _defaultDownloaderConfig;
|
|||
SDWebImageDownloaderConfig *config = [[[self class] allocWithZone:zone] init];
|
||||
config.maxConcurrentDownloads = self.maxConcurrentDownloads;
|
||||
config.downloadTimeout = self.downloadTimeout;
|
||||
config.minimumProgressInterval = self.minimumProgressInterval;
|
||||
config.sessionConfiguration = [self.sessionConfiguration copyWithZone:zone];
|
||||
config.operationClass = self.operationClass;
|
||||
config.executionOrder = self.executionOrder;
|
||||
|
|
|
@ -36,9 +36,6 @@ FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadFinishNotification
|
|||
- (nullable id)addHandlersForProgress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
|
||||
completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock;
|
||||
|
||||
- (nullable NSURLCredential *)credential;
|
||||
- (void)setCredential:(nullable NSURLCredential *)value;
|
||||
|
||||
- (BOOL)cancel:(nullable id)token;
|
||||
|
||||
- (nullable NSURLRequest *)request;
|
||||
|
@ -46,6 +43,10 @@ FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadFinishNotification
|
|||
|
||||
@optional
|
||||
- (nullable NSURLSessionTask *)dataTask;
|
||||
- (nullable NSURLCredential *)credential;
|
||||
- (void)setCredential:(nullable NSURLCredential *)credential;
|
||||
- (NSTimeInterval)minimumProgressInterval;
|
||||
- (void)setMinimumProgressInterval:(NSTimeInterval)minimumProgressInterval;
|
||||
|
||||
@end
|
||||
|
||||
|
@ -74,6 +75,15 @@ FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadFinishNotification
|
|||
*/
|
||||
@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.
|
||||
*/
|
||||
|
|
|
@ -37,9 +37,11 @@ typedef NSMutableDictionary<NSString *, id> SDCallbacksDictionary;
|
|||
@property (assign, nonatomic, getter = isFinished) BOOL finished;
|
||||
@property (strong, nonatomic, nullable) NSMutableData *imageData;
|
||||
@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) 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
|
||||
// the task associated with this operation
|
||||
|
@ -331,17 +333,37 @@ didReceiveResponse:(NSURLResponse *)response
|
|||
self.imageData = [[NSMutableData alloc] initWithCapacity:self.expectedSize];
|
||||
}
|
||||
[self.imageData appendData:data];
|
||||
|
||||
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) && self.expectedSize > 0) {
|
||||
if (self.options & SDWebImageDownloaderProgressiveLoad) {
|
||||
// Get the image data
|
||||
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
|
||||
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);
|
||||
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.
|
||||
|
@ -350,9 +372,9 @@ didReceiveResponse:(NSURLResponse *)response
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
for (SDWebImageDownloaderProgressBlock progressBlock in [self callbacksForKey:kProgressCallbackKey]) {
|
||||
progressBlock(self.imageData.length, self.expectedSize, self.request.URL);
|
||||
progressBlock(self.receivedSize, self.expectedSize, self.request.URL);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -259,6 +259,34 @@
|
|||
[self waitForExpectationsWithCommonTimeout];
|
||||
}
|
||||
|
||||
- (void)test17ThatMinimumProgressIntervalWorks {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"Minimum progress interval"];
|
||||
SDWebImageDownloaderConfig *config = SDWebImageDownloaderConfig.defaultDownloaderConfig;
|
||||
config.minimumProgressInterval = 0.51; // This will make the progress only callback once
|
||||
SDWebImageDownloader *downloader = [[SDWebImageDownloader alloc] initWithConfig:config];
|
||||
NSURL *imageURL = [NSURL URLWithString:@"http://www.ioncannon.net/wp-content/uploads/2011/06/test2.webp"];
|
||||
__block NSUInteger allProgressCount = 0; // All progress (including operation start / first HTTP response, etc)
|
||||
__block NSUInteger validProgressCount = 0; // Only progress from `URLSession:dataTask:didReceiveData:`
|
||||
[downloader downloadImageWithURL:imageURL options:0 progress:^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) {
|
||||
allProgressCount++;
|
||||
if (expectedSize <= 0 || receivedSize <= 0) {
|
||||
// ignore the progress callback until we receive data
|
||||
return;
|
||||
}
|
||||
validProgressCount++;
|
||||
} completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) {
|
||||
if (allProgressCount > 1 && validProgressCount == 1) {
|
||||
[expectation fulfill];
|
||||
} else {
|
||||
XCTFail(@"Progress callback more than once");
|
||||
}
|
||||
}];
|
||||
|
||||
[self waitForExpectationsWithCommonTimeoutUsingHandler:^(NSError * _Nullable error) {
|
||||
[downloader invalidateSessionAndCancel:YES];
|
||||
}];
|
||||
}
|
||||
|
||||
/**
|
||||
* Per #883 - Fix multiple requests for same image and then canceling one
|
||||
* Old SDWebImage (3.x) could not handle correctly multiple requests for the same image + cancel
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
*/
|
||||
@interface SDWebImageTestDownloadOperation : NSOperation <SDWebImageDownloaderOperation>
|
||||
|
||||
@property (nonatomic, strong, nullable) NSURLCredential *credential;
|
||||
@property (nonatomic, strong, nullable) NSURLRequest *request;
|
||||
@property (nonatomic, strong, nullable) NSURLResponse *response;
|
||||
|
||||
|
|
Loading…
Reference in New Issue