Merge pull request #2937 from dreampiggy/feature_URLSessionTaskMetrics
Added the URLSessionTaskMetrics support for downloader && operation, which can be used for network metrics
This commit is contained in:
commit
bbfe690845
|
@ -113,10 +113,22 @@
|
|||
}
|
||||
|
||||
cell.customTextLabel.text = [NSString stringWithFormat:@"Image #%ld", (long)indexPath.row];
|
||||
[cell.customImageView sd_setImageWithURL:[NSURL URLWithString:self.objects[indexPath.row]]
|
||||
placeholderImage:placeholderImage
|
||||
options:indexPath.row == 0 ? SDWebImageRefreshCached : 0
|
||||
context:@{SDWebImageContextImageThumbnailPixelSize : @(CGSizeMake(180, 120))}];
|
||||
__weak SDAnimatedImageView *imageView = cell.customImageView;
|
||||
[imageView sd_setImageWithURL:[NSURL URLWithString:self.objects[indexPath.row]]
|
||||
placeholderImage:placeholderImage
|
||||
options:indexPath.row == 0 ? SDWebImageRefreshCached : 0
|
||||
context:@{SDWebImageContextImageThumbnailPixelSize : @(CGSizeMake(180, 120))}
|
||||
progress:nil
|
||||
completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
|
||||
SDWebImageCombinedOperation *operation = [imageView sd_imageLoadOperationForKey:imageView.sd_latestOperationKey];
|
||||
SDWebImageDownloadToken *token = operation.loaderOperation;
|
||||
if (@available(iOS 10.0, *)) {
|
||||
NSURLSessionTaskMetrics *metrics = token.metrics;
|
||||
if (metrics) {
|
||||
printf("Metrics: %s download in (%f) seconds\n", [imageURL.absoluteString cStringUsingEncoding:NSUTF8StringEncoding], metrics.taskInterval.duration);
|
||||
}
|
||||
}
|
||||
}];
|
||||
return cell;
|
||||
}
|
||||
|
||||
|
|
|
@ -128,6 +128,11 @@ typedef SDImageLoaderCompletedBlock SDWebImageDownloaderCompletedBlock;
|
|||
*/
|
||||
@property (nonatomic, strong, nullable, readonly) NSURLResponse *response;
|
||||
|
||||
/**
|
||||
The download's metrics. This will be nil if download operation does not support metrics.
|
||||
*/
|
||||
@property (nonatomic, strong, nullable, readonly) NSURLSessionTaskMetrics *metrics API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext;
|
|||
@property (nonatomic, strong, nullable, readwrite) NSURL *url;
|
||||
@property (nonatomic, strong, nullable, readwrite) NSURLRequest *request;
|
||||
@property (nonatomic, strong, nullable, readwrite) NSURLResponse *response;
|
||||
@property (nonatomic, strong, nullable, readwrite) NSURLSessionTaskMetrics *metrics API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
|
||||
@property (nonatomic, weak, nullable, readwrite) id downloadOperationCancelToken;
|
||||
@property (nonatomic, weak, nullable) NSOperation<SDWebImageDownloaderOperation> *downloadOperation;
|
||||
@property (nonatomic, assign, getter=isCancelled) BOOL cancelled;
|
||||
|
@ -498,6 +499,15 @@ didReceiveResponse:(NSURLResponse *)response
|
|||
}
|
||||
}
|
||||
|
||||
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)metrics API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0)) {
|
||||
|
||||
// Identify the operation that runs this task and pass it the delegate method
|
||||
NSOperation<SDWebImageDownloaderOperation> *dataOperation = [self operationWithTask:task];
|
||||
if ([dataOperation respondsToSelector:@selector(URLSession:task:didFinishCollectingMetrics:)]) {
|
||||
[dataOperation URLSession:session task:task didFinishCollectingMetrics:metrics];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation SDWebImageDownloadToken
|
||||
|
@ -510,18 +520,30 @@ didReceiveResponse:(NSURLResponse *)response
|
|||
self = [super init];
|
||||
if (self) {
|
||||
_downloadOperation = downloadOperation;
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(downloadReceiveResponse:) name:SDWebImageDownloadReceiveResponseNotification object:downloadOperation];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(downloadDidReceiveResponse:) name:SDWebImageDownloadReceiveResponseNotification object:downloadOperation];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(downloadDidStop:) name:SDWebImageDownloadStopNotification object:downloadOperation];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)downloadReceiveResponse:(NSNotification *)notification {
|
||||
- (void)downloadDidReceiveResponse:(NSNotification *)notification {
|
||||
NSOperation<SDWebImageDownloaderOperation> *downloadOperation = notification.object;
|
||||
if (downloadOperation && downloadOperation == self.downloadOperation) {
|
||||
self.response = downloadOperation.response;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)downloadDidStop:(NSNotification *)notification {
|
||||
NSOperation<SDWebImageDownloaderOperation> *downloadOperation = notification.object;
|
||||
if (downloadOperation && downloadOperation == self.downloadOperation) {
|
||||
if ([downloadOperation respondsToSelector:@selector(metrics)]) {
|
||||
if (@available(iOS 10.0, tvOS 10.0, macOS 10.12, watchOS 3.0, *)) {
|
||||
self.metrics = downloadOperation.metrics;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)cancel {
|
||||
@synchronized (self) {
|
||||
if (self.isCancelled) {
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
|
||||
@optional
|
||||
@property (strong, nonatomic, readonly, nullable) NSURLSessionTask *dataTask;
|
||||
@property (strong, nonatomic, readonly, nullable) NSURLSessionTaskMetrics *metrics API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
|
||||
@property (strong, nonatomic, nullable) NSURLCredential *credential;
|
||||
@property (assign, nonatomic) double minimumProgressInterval;
|
||||
|
||||
|
@ -62,6 +63,12 @@
|
|||
*/
|
||||
@property (strong, nonatomic, readonly, nullable) NSURLSessionTask *dataTask;
|
||||
|
||||
/**
|
||||
* The collected metrics from `-URLSession:task:didFinishCollectingMetrics:`.
|
||||
* This can be used to collect the network metrics like download duration, DNS lookup duration, SSL handshake dureation, etc. See Apple's documentation: https://developer.apple.com/documentation/foundation/urlsessiontaskmetrics
|
||||
*/
|
||||
@property (strong, nonatomic, readonly, nullable) NSURLSessionTaskMetrics *metrics API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
|
||||
|
||||
/**
|
||||
* The credential used for authentication challenges in `-URLSession:task:didReceiveChallenge:completionHandler:`.
|
||||
*
|
||||
|
|
|
@ -52,6 +52,8 @@ typedef NSMutableDictionary<NSString *, id> SDCallbacksDictionary;
|
|||
|
||||
@property (strong, nonatomic, readwrite, nullable) NSURLSessionTask *dataTask;
|
||||
|
||||
@property (strong, nonatomic, readwrite, nullable) NSURLSessionTaskMetrics *metrics API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
|
||||
|
||||
@property (strong, nonatomic, nonnull) dispatch_queue_t coderQueue; // the queue to do image decoding
|
||||
#if SD_UIKIT
|
||||
@property (assign, nonatomic) UIBackgroundTaskIdentifier backgroundTaskId;
|
||||
|
@ -512,6 +514,10 @@ didReceiveResponse:(NSURLResponse *)response
|
|||
}
|
||||
}
|
||||
|
||||
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)metrics API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0)) {
|
||||
self.metrics = metrics;
|
||||
}
|
||||
|
||||
#pragma mark Helper methods
|
||||
+ (SDWebImageOptions)imageOptionsFromDownloaderOptions:(SDWebImageDownloaderOptions)downloadOptions {
|
||||
SDWebImageOptions options = 0;
|
||||
|
|
|
@ -31,6 +31,13 @@ typedef void(^SDSetImageBlock)(UIImage * _Nullable image, NSData * _Nullable ima
|
|||
*/
|
||||
@property (nonatomic, strong, readonly, nullable) NSURL *sd_imageURL;
|
||||
|
||||
/**
|
||||
* Get the current image operation key. Operation key is used to identify the different queries for one view instance (like UIButton).
|
||||
* See more about this in `SDWebImageContextSetImageOperationKey`.
|
||||
* @note You can use method `UIView+WebCacheOperation` to invesigate different queries' operation.
|
||||
*/
|
||||
@property (nonatomic, strong, readonly, nullable) NSString *sd_latestOperationKey;
|
||||
|
||||
/**
|
||||
* The current image loading progress associated to the view. The unit count is the received size and excepted size of download.
|
||||
* The `totalUnitCount` and `completedUnitCount` will be reset to 0 after a new image loading start (change from current queue). And they will be set to `SDWebImageProgressUnitCountUnknown` if the progressBlock not been called but the image loading success to mark the progress finished (change from main queue).
|
||||
|
|
|
@ -642,6 +642,37 @@
|
|||
}];
|
||||
}
|
||||
|
||||
- (void)test26DownloadURLSessionMetrics {
|
||||
XCTestExpectation *expectation1 = [self expectationWithDescription:@"Download URLSessionMetrics works"];
|
||||
|
||||
SDWebImageDownloader *downloader = [[SDWebImageDownloader alloc] init];
|
||||
|
||||
__block SDWebImageDownloadToken *token;
|
||||
token = [downloader downloadImageWithURL:[NSURL URLWithString:kTestJPEGURL] completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) {
|
||||
expect(error).beNil();
|
||||
if (@available(iOS 10.0, tvOS 10.0, macOS 10.12, *)) {
|
||||
NSURLSessionTaskMetrics *metrics = token.metrics;
|
||||
expect(metrics).notTo.beNil();
|
||||
expect(metrics.redirectCount).equal(0);
|
||||
expect(metrics.transactionMetrics.count).equal(1);
|
||||
NSURLSessionTaskTransactionMetrics *metric = metrics.transactionMetrics.firstObject;
|
||||
// Metrcis Test
|
||||
expect(metric.fetchStartDate).notTo.beNil();
|
||||
expect(metric.connectStartDate).notTo.beNil();
|
||||
expect(metric.connectEndDate).notTo.beNil();
|
||||
expect(metric.networkProtocolName).equal(@"http/1.1");
|
||||
expect(metric.resourceFetchType).equal(NSURLSessionTaskMetricsResourceFetchTypeNetworkLoad);
|
||||
expect(metric.isProxyConnection).beFalsy();
|
||||
expect(metric.isReusedConnection).beFalsy();
|
||||
}
|
||||
[expectation1 fulfill];
|
||||
}];
|
||||
|
||||
[self waitForExpectationsWithCommonTimeoutUsingHandler:^(NSError * _Nullable error) {
|
||||
[downloader invalidateSessionAndCancel:YES];
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - SDWebImageLoader
|
||||
- (void)test30CustomImageLoaderWorks {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"Custom image not works"];
|
||||
|
|
Loading…
Reference in New Issue