mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-09-04 20:00:53 +00:00
Experiment with different strategies for image downloader priority (#1349)
Right now when an image node enters preload state, we kick off an image request with the default priority. Then when it enters display state, we change the priority to "imminent" which is mapped to the default priority as well. This means that requests from preload and display nodes have the same priority and are put to the same pool. The right behavior would be that preload requests should have a lower priority from the beginning. Another problem is that, due to the execution order of -didEnter(Preload|Display|Visible)State calls, a node may kick off a low priority request when it enters preload state even though it knows that it's also visible. By the time -didEnterVisibleState is called, the low priority request may have already been consumed and the download/data task won't pick up the new higher priority, or some work needs to be done to move it to another queue. A better behavior would be to always use the current interface state to determine the priority. This means that visible nodes will kick off high priority requests as soon as -didEnterPreloadState is called. The last (and smaller) issue is that a node marks its request as preload/low priority as soon as it exits visible state. I'd argue that this is too agressive. It may be reasonble for nodes in the trailing direction. Even so, we already handle this case by (almost always) have smaller trailing buffers. So this diff makes sure that nodes that exited visible state will have imminent/default priority if they remain in the display range. All of these new behaviors are wrapped in an experiment and will be tested carefully before being rolled out. * Add imports * Fix build failure * Encapsulate common logics into methods * Address comments
This commit is contained in:
parent
5e8721ebe8
commit
d102ec81ee
39
Podfile.lock
39
Podfile.lock
@ -1,38 +1,32 @@
|
|||||||
PODS:
|
PODS:
|
||||||
- FBSnapshotTestCase/Core (2.1.4)
|
- FBSnapshotTestCase/Core (2.1.4)
|
||||||
- FLAnimatedImage (1.0.12)
|
|
||||||
- JGMethodSwizzler (2.0.1)
|
- JGMethodSwizzler (2.0.1)
|
||||||
- OCMock (3.4.1)
|
- OCMock (3.4.1)
|
||||||
- PINCache (3.0.1-beta.6):
|
- PINCache (3.0.1-beta.7):
|
||||||
- PINCache/Arc-exception-safe (= 3.0.1-beta.6)
|
- PINCache/Arc-exception-safe (= 3.0.1-beta.7)
|
||||||
- PINCache/Core (= 3.0.1-beta.6)
|
- PINCache/Core (= 3.0.1-beta.7)
|
||||||
- PINCache/Arc-exception-safe (3.0.1-beta.6):
|
- PINCache/Arc-exception-safe (3.0.1-beta.7):
|
||||||
- PINCache/Core
|
- PINCache/Core
|
||||||
- PINCache/Core (3.0.1-beta.6):
|
- PINCache/Core (3.0.1-beta.7):
|
||||||
- PINOperation (~> 1.1.0)
|
- PINOperation (~> 1.1.1)
|
||||||
- PINOperation (1.1.1)
|
- PINOperation (1.1.1)
|
||||||
- PINRemoteImage (3.0.0-beta.13):
|
- PINRemoteImage (3.0.0-beta.14):
|
||||||
- PINRemoteImage/FLAnimatedImage (= 3.0.0-beta.13)
|
- PINRemoteImage/PINCache (= 3.0.0-beta.14)
|
||||||
- PINRemoteImage/PINCache (= 3.0.0-beta.13)
|
- PINRemoteImage/Core (3.0.0-beta.14):
|
||||||
- PINRemoteImage/Core (3.0.0-beta.13):
|
|
||||||
- PINOperation
|
- PINOperation
|
||||||
- PINRemoteImage/FLAnimatedImage (3.0.0-beta.13):
|
- PINRemoteImage/PINCache (3.0.0-beta.14):
|
||||||
- FLAnimatedImage (>= 1.0)
|
- PINCache (= 3.0.1-beta.7)
|
||||||
- PINRemoteImage/Core
|
|
||||||
- PINRemoteImage/PINCache (3.0.0-beta.13):
|
|
||||||
- PINCache (= 3.0.1-beta.6)
|
|
||||||
- PINRemoteImage/Core
|
- PINRemoteImage/Core
|
||||||
|
|
||||||
DEPENDENCIES:
|
DEPENDENCIES:
|
||||||
- FBSnapshotTestCase/Core (~> 2.1)
|
- FBSnapshotTestCase/Core (~> 2.1)
|
||||||
- JGMethodSwizzler (from `https://github.com/JonasGessner/JGMethodSwizzler`, branch `master`)
|
- JGMethodSwizzler (from `https://github.com/JonasGessner/JGMethodSwizzler`, branch `master`)
|
||||||
- OCMock (= 3.4.1)
|
- OCMock (= 3.4.1)
|
||||||
- PINRemoteImage (= 3.0.0-beta.13)
|
- PINRemoteImage (= 3.0.0-beta.14)
|
||||||
|
|
||||||
SPEC REPOS:
|
SPEC REPOS:
|
||||||
https://github.com/cocoapods/specs.git:
|
https://github.com/cocoapods/specs.git:
|
||||||
- FBSnapshotTestCase
|
- FBSnapshotTestCase
|
||||||
- FLAnimatedImage
|
|
||||||
- OCMock
|
- OCMock
|
||||||
- PINCache
|
- PINCache
|
||||||
- PINOperation
|
- PINOperation
|
||||||
@ -50,13 +44,12 @@ CHECKOUT OPTIONS:
|
|||||||
|
|
||||||
SPEC CHECKSUMS:
|
SPEC CHECKSUMS:
|
||||||
FBSnapshotTestCase: 094f9f314decbabe373b87cc339bea235a63e07a
|
FBSnapshotTestCase: 094f9f314decbabe373b87cc339bea235a63e07a
|
||||||
FLAnimatedImage: 4a0b56255d9b05f18b6dd7ee06871be5d3b89e31
|
|
||||||
JGMethodSwizzler: 7328146117fffa8a4038c42eb7cd3d4c75006f97
|
JGMethodSwizzler: 7328146117fffa8a4038c42eb7cd3d4c75006f97
|
||||||
OCMock: 2cd0716969bab32a2283ff3a46fd26a8c8b4c5e3
|
OCMock: 2cd0716969bab32a2283ff3a46fd26a8c8b4c5e3
|
||||||
PINCache: d195fdba255283f7e9900a55e3cced377f431f9b
|
PINCache: 7cb9ae068c8f655717f7c644ef1dff9fd573e979
|
||||||
PINOperation: a6219e6fc9db9c269eb7a7b871ac193bcf400aac
|
PINOperation: a6219e6fc9db9c269eb7a7b871ac193bcf400aac
|
||||||
PINRemoteImage: d6d51c5d2adda55f1ce30c96e850b6c4ebd2856a
|
PINRemoteImage: 81bbff853acc71c6de9e106e9e489a791b8bbb08
|
||||||
|
|
||||||
PODFILE CHECKSUM: 42715d61f73cc22cc116bf80d7b268cb1f9e4742
|
PODFILE CHECKSUM: 445046ac151568c694ff286684322273f0b597d6
|
||||||
|
|
||||||
COCOAPODS: 1.5.3
|
COCOAPODS: 1.6.0
|
||||||
|
@ -25,7 +25,8 @@
|
|||||||
"exp_disable_a11y_cache",
|
"exp_disable_a11y_cache",
|
||||||
"exp_skip_a11y_wait",
|
"exp_skip_a11y_wait",
|
||||||
"exp_new_default_cell_layout_mode",
|
"exp_new_default_cell_layout_mode",
|
||||||
"exp_dispatch_apply"
|
"exp_dispatch_apply",
|
||||||
|
"exp_image_downloader_priority"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,7 @@ typedef NS_OPTIONS(NSUInteger, ASExperimentalFeatures) {
|
|||||||
ASExperimentalSkipAccessibilityWait = 1 << 10, // exp_skip_a11y_wait
|
ASExperimentalSkipAccessibilityWait = 1 << 10, // exp_skip_a11y_wait
|
||||||
ASExperimentalNewDefaultCellLayoutMode = 1 << 11, // exp_new_default_cell_layout_mode
|
ASExperimentalNewDefaultCellLayoutMode = 1 << 11, // exp_new_default_cell_layout_mode
|
||||||
ASExperimentalDispatchApply = 1 << 12, // exp_dispatch_apply
|
ASExperimentalDispatchApply = 1 << 12, // exp_dispatch_apply
|
||||||
|
ASExperimentalImageDownloaderPriority = 1 << 13, // exp_image_downloader_priority
|
||||||
ASExperimentalFeatureAll = 0xFFFFFFFF
|
ASExperimentalFeatureAll = 0xFFFFFFFF
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -24,8 +24,9 @@ NSArray<NSString *> *ASExperimentalFeaturesGetNames(ASExperimentalFeatures flags
|
|||||||
@"exp_disable_a11y_cache",
|
@"exp_disable_a11y_cache",
|
||||||
@"exp_skip_a11y_wait",
|
@"exp_skip_a11y_wait",
|
||||||
@"exp_new_default_cell_layout_mode",
|
@"exp_new_default_cell_layout_mode",
|
||||||
@"exp_dispatch_apply"]));
|
@"exp_dispatch_apply",
|
||||||
|
@"exp_image_downloader_priority"]));
|
||||||
|
|
||||||
if (flags == ASExperimentalFeatureAll) {
|
if (flags == ASExperimentalFeatureAll) {
|
||||||
return allNames;
|
return allNames;
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,13 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent
|
|||||||
@private
|
@private
|
||||||
// Core.
|
// Core.
|
||||||
id<ASImageCacheProtocol> _cache;
|
id<ASImageCacheProtocol> _cache;
|
||||||
|
|
||||||
id<ASImageDownloaderProtocol> _downloader;
|
id<ASImageDownloaderProtocol> _downloader;
|
||||||
|
struct {
|
||||||
|
unsigned int downloaderImplementsSetProgress:1;
|
||||||
|
unsigned int downloaderImplementsSetPriority:1;
|
||||||
|
unsigned int downloaderImplementsDownloadWithPriority:1;
|
||||||
|
} _downloaderFlags;
|
||||||
|
|
||||||
__weak id<ASMultiplexImageNodeDelegate> _delegate;
|
__weak id<ASMultiplexImageNodeDelegate> _delegate;
|
||||||
struct {
|
struct {
|
||||||
@ -89,8 +95,6 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent
|
|||||||
BOOL _shouldRenderProgressImages;
|
BOOL _shouldRenderProgressImages;
|
||||||
|
|
||||||
//set on init only
|
//set on init only
|
||||||
BOOL _downloaderImplementsSetProgress;
|
|
||||||
BOOL _downloaderImplementsSetPriority;
|
|
||||||
BOOL _cacheSupportsClearing;
|
BOOL _cacheSupportsClearing;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,13 +175,14 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent
|
|||||||
_cache = (id<ASImageCacheProtocol>)cache;
|
_cache = (id<ASImageCacheProtocol>)cache;
|
||||||
_downloader = (id<ASImageDownloaderProtocol>)downloader;
|
_downloader = (id<ASImageDownloaderProtocol>)downloader;
|
||||||
|
|
||||||
_downloaderImplementsSetProgress = [downloader respondsToSelector:@selector(setProgressImageBlock:callbackQueue:withDownloadIdentifier:)];
|
_downloaderFlags.downloaderImplementsSetProgress = [downloader respondsToSelector:@selector(setProgressImageBlock:callbackQueue:withDownloadIdentifier:)];
|
||||||
_downloaderImplementsSetPriority = [downloader respondsToSelector:@selector(setPriority:withDownloadIdentifier:)];
|
_downloaderFlags.downloaderImplementsSetPriority = [downloader respondsToSelector:@selector(setPriority:withDownloadIdentifier:)];
|
||||||
|
_downloaderFlags.downloaderImplementsDownloadWithPriority = [downloader respondsToSelector:@selector(downloadImageWithURL:priority:callbackQueue:downloadProgress:completion:)];
|
||||||
|
|
||||||
_cacheSupportsClearing = [cache respondsToSelector:@selector(clearFetchedImageFromCacheWithURL:)];
|
_cacheSupportsClearing = [cache respondsToSelector:@selector(clearFetchedImageFromCacheWithURL:)];
|
||||||
|
|
||||||
_shouldRenderProgressImages = YES;
|
_shouldRenderProgressImages = YES;
|
||||||
|
|
||||||
self.shouldBypassEnsureDisplay = YES;
|
self.shouldBypassEnsureDisplay = YES;
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@ -271,17 +276,8 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent
|
|||||||
- (void)displayWillStartAsynchronously:(BOOL)asynchronously
|
- (void)displayWillStartAsynchronously:(BOOL)asynchronously
|
||||||
{
|
{
|
||||||
[super displayWillStartAsynchronously:asynchronously];
|
[super displayWillStartAsynchronously:asynchronously];
|
||||||
|
|
||||||
[self didEnterPreloadState];
|
[self didEnterPreloadState];
|
||||||
|
[self _updatePriorityOnDownloaderIfNeededWithDefaultPriority:ASImageDownloaderPriorityImminent];
|
||||||
if (_downloaderImplementsSetPriority) {
|
|
||||||
{
|
|
||||||
ASDN::MutexLocker l(_downloadIdentifierLock);
|
|
||||||
if (_downloadIdentifier != nil) {
|
|
||||||
[_downloader setPriority:ASImageDownloaderPriorityImminent withDownloadIdentifier:_downloadIdentifier];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* didEnterVisibleState / didExitVisibleState in ASNetworkImageNode has a very similar implementation. Changes here are likely necessary
|
/* didEnterVisibleState / didExitVisibleState in ASNetworkImageNode has a very similar implementation. Changes here are likely necessary
|
||||||
@ -289,31 +285,25 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent
|
|||||||
- (void)didEnterVisibleState
|
- (void)didEnterVisibleState
|
||||||
{
|
{
|
||||||
[super didEnterVisibleState];
|
[super didEnterVisibleState];
|
||||||
|
[self _updatePriorityOnDownloaderIfNeededWithDefaultPriority:ASImageDownloaderPriorityVisible];
|
||||||
if (_downloaderImplementsSetPriority) {
|
|
||||||
ASDN::MutexLocker l(_downloadIdentifierLock);
|
|
||||||
if (_downloadIdentifier != nil) {
|
|
||||||
[_downloader setPriority:ASImageDownloaderPriorityVisible withDownloadIdentifier:_downloadIdentifier];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[self _updateProgressImageBlockOnDownloaderIfNeeded];
|
[self _updateProgressImageBlockOnDownloaderIfNeeded];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)didExitVisibleState
|
- (void)didExitVisibleState
|
||||||
{
|
{
|
||||||
[super didExitVisibleState];
|
[super didExitVisibleState];
|
||||||
|
[self _updatePriorityOnDownloaderIfNeededWithDefaultPriority:ASImageDownloaderPriorityPreload];
|
||||||
if (_downloaderImplementsSetPriority) {
|
|
||||||
ASDN::MutexLocker l(_downloadIdentifierLock);
|
|
||||||
if (_downloadIdentifier != nil) {
|
|
||||||
[_downloader setPriority:ASImageDownloaderPriorityPreload withDownloadIdentifier:_downloadIdentifier];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[self _updateProgressImageBlockOnDownloaderIfNeeded];
|
[self _updateProgressImageBlockOnDownloaderIfNeeded];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)didExitDisplayState
|
||||||
|
{
|
||||||
|
[super didExitDisplayState];
|
||||||
|
if (ASActivateExperimentalFeature(ASExperimentalImageDownloaderPriority)) {
|
||||||
|
[self _updatePriorityOnDownloaderIfNeededWithDefaultPriority:ASImageDownloaderPriorityPreload];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark - Core
|
#pragma mark - Core
|
||||||
|
|
||||||
- (void)setImage:(UIImage *)image
|
- (void)setImage:(UIImage *)image
|
||||||
@ -449,7 +439,6 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent
|
|||||||
_downloadIdentifier = downloadIdentifier;
|
_downloadIdentifier = downloadIdentifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#pragma mark - Image Loading Machinery
|
#pragma mark - Image Loading Machinery
|
||||||
|
|
||||||
- (void)_loadImageIdentifiers
|
- (void)_loadImageIdentifiers
|
||||||
@ -493,19 +482,37 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent
|
|||||||
|
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
|
|
||||||
/**
|
- (void)_updatePriorityOnDownloaderIfNeededWithDefaultPriority:(ASImageDownloaderPriority)defaultPriority
|
||||||
@note: This should be called without _downloadIdentifierLock held. We will lock
|
{
|
||||||
super to read our interface state and it's best to avoid acquiring both locks.
|
ASAssertUnlocked(_downloadIdentifierLock);
|
||||||
*/
|
|
||||||
|
if (_downloaderFlags.downloaderImplementsSetPriority) {
|
||||||
|
// Read our interface state before locking so that we don't lock super while holding our lock.
|
||||||
|
ASInterfaceState interfaceState = self.interfaceState;
|
||||||
|
ASDN::MutexLocker l(_downloadIdentifierLock);
|
||||||
|
|
||||||
|
if (_downloadIdentifier != nil) {
|
||||||
|
ASImageDownloaderPriority priority = defaultPriority;
|
||||||
|
if (ASActivateExperimentalFeature(ASExperimentalImageDownloaderPriority)) {
|
||||||
|
priority = ASImageDownloaderPriorityWithInterfaceState(interfaceState);
|
||||||
|
}
|
||||||
|
|
||||||
|
[_downloader setPriority:priority withDownloadIdentifier:_downloadIdentifier];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
- (void)_updateProgressImageBlockOnDownloaderIfNeeded
|
- (void)_updateProgressImageBlockOnDownloaderIfNeeded
|
||||||
{
|
{
|
||||||
|
ASAssertUnlocked(_downloadIdentifierLock);
|
||||||
|
|
||||||
BOOL shouldRenderProgressImages = self.shouldRenderProgressImages;
|
BOOL shouldRenderProgressImages = self.shouldRenderProgressImages;
|
||||||
|
|
||||||
// Read our interface state before locking so that we don't lock super while holding our lock.
|
// Read our interface state before locking so that we don't lock super while holding our lock.
|
||||||
ASInterfaceState interfaceState = self.interfaceState;
|
ASInterfaceState interfaceState = self.interfaceState;
|
||||||
ASDN::MutexLocker l(_downloadIdentifierLock);
|
ASDN::MutexLocker l(_downloadIdentifierLock);
|
||||||
|
|
||||||
if (!_downloaderImplementsSetProgress || _downloadIdentifier == nil) {
|
if (!_downloaderFlags.downloaderImplementsSetProgress || _downloadIdentifier == nil) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -825,7 +832,7 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent
|
|||||||
[_delegate multiplexImageNode:self didStartDownloadOfImageWithIdentifier:imageIdentifier];
|
[_delegate multiplexImageNode:self didStartDownloadOfImageWithIdentifier:imageIdentifier];
|
||||||
|
|
||||||
__weak __typeof__(self) weakSelf = self;
|
__weak __typeof__(self) weakSelf = self;
|
||||||
void (^downloadProgressBlock)(CGFloat) = nil;
|
ASImageDownloaderProgress downloadProgressBlock = NULL;
|
||||||
if (_delegateFlags.downloadProgress) {
|
if (_delegateFlags.downloadProgress) {
|
||||||
downloadProgressBlock = ^(CGFloat progress) {
|
downloadProgressBlock = ^(CGFloat progress) {
|
||||||
__typeof__(self) strongSelf = weakSelf;
|
__typeof__(self) strongSelf = weakSelf;
|
||||||
@ -835,30 +842,67 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ASImageDownloaderCompletion completion = ^(id <ASImageContainerProtocol> imageContainer, NSError *error, id downloadIdentifier, id userInfo) {
|
||||||
|
// We dereference iVars directly, so we can't have weakSelf going nil on us.
|
||||||
|
__typeof__(self) strongSelf = weakSelf;
|
||||||
|
if (!strongSelf)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ASDN::MutexLocker l(strongSelf->_downloadIdentifierLock);
|
||||||
|
//Getting a result back for a different download identifier, download must not have been successfully canceled
|
||||||
|
if (ASObjectIsEqual(strongSelf->_downloadIdentifier, downloadIdentifier) == NO && downloadIdentifier != nil) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
completionBlock([imageContainer asdk_image], error);
|
||||||
|
|
||||||
|
// Delegateify.
|
||||||
|
if (strongSelf->_delegateFlags.downloadFinish)
|
||||||
|
[strongSelf->_delegate multiplexImageNode:weakSelf didFinishDownloadingImageWithIdentifier:imageIdentifier error:error];
|
||||||
|
};
|
||||||
|
|
||||||
// Download!
|
// Download!
|
||||||
ASPerformBlockOnBackgroundThread(^{
|
ASPerformBlockOnBackgroundThread(^{
|
||||||
[self _setDownloadIdentifier:[_downloader downloadImageWithURL:imageURL
|
__typeof__(self) strongSelf = weakSelf;
|
||||||
callbackQueue:dispatch_get_main_queue()
|
if (!strongSelf)
|
||||||
downloadProgress:downloadProgressBlock
|
return;
|
||||||
completion:^(id <ASImageContainerProtocol> imageContainer, NSError *error, id downloadIdentifier, id userInfo) {
|
|
||||||
// We dereference iVars directly, so we can't have weakSelf going nil on us.
|
dispatch_queue_t callbackQueue = dispatch_get_main_queue();
|
||||||
__typeof__(self) strongSelf = weakSelf;
|
|
||||||
if (!strongSelf)
|
id downloadIdentifier;
|
||||||
return;
|
if (strongSelf->_downloaderFlags.downloaderImplementsDownloadWithPriority
|
||||||
|
&& ASActivateExperimentalFeature(ASExperimentalImageDownloaderPriority)) {
|
||||||
ASDN::MutexLocker l(_downloadIdentifierLock);
|
|
||||||
//Getting a result back for a different download identifier, download must not have been successfully canceled
|
/*
|
||||||
if (ASObjectIsEqual(_downloadIdentifier, downloadIdentifier) == NO && downloadIdentifier != nil) {
|
Decide a priority based on the current interface state of this node.
|
||||||
return;
|
It can happen that this method was called when the node entered preload state
|
||||||
}
|
but the interface state, at this point, tells us that the node is (going to be) visible,
|
||||||
|
If that's the case, we jump to a higher priority directly.
|
||||||
completionBlock([imageContainer asdk_image], error);
|
*/
|
||||||
|
ASImageDownloaderPriority priority = ASImageDownloaderPriorityWithInterfaceState(strongSelf.interfaceState);
|
||||||
// Delegateify.
|
downloadIdentifier = [strongSelf->_downloader downloadImageWithURL:imageURL
|
||||||
if (strongSelf->_delegateFlags.downloadFinish)
|
priority:priority
|
||||||
[strongSelf->_delegate multiplexImageNode:weakSelf didFinishDownloadingImageWithIdentifier:imageIdentifier error:error];
|
callbackQueue:callbackQueue
|
||||||
}]];
|
downloadProgress:downloadProgressBlock
|
||||||
[self _updateProgressImageBlockOnDownloaderIfNeeded];
|
completion:completion];
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
Kick off a download with default priority.
|
||||||
|
The actual "default" value is decided by the downloader.
|
||||||
|
ASBasicImageDownloader and ASPINRemoteImageDownloader both use ASImageDownloaderPriorityImminent
|
||||||
|
which is mapped to NSURLSessionTaskPriorityDefault.
|
||||||
|
|
||||||
|
This means that preload and display nodes use the same priority
|
||||||
|
and their requests are put into the same pool.
|
||||||
|
*/
|
||||||
|
downloadIdentifier = [strongSelf->_downloader downloadImageWithURL:imageURL
|
||||||
|
callbackQueue:callbackQueue
|
||||||
|
downloadProgress:downloadProgressBlock
|
||||||
|
completion:completion];
|
||||||
|
}
|
||||||
|
|
||||||
|
[strongSelf _setDownloadIdentifier:downloadIdentifier];
|
||||||
|
[strongSelf _updateProgressImageBlockOnDownloaderIfNeeded];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,6 +68,7 @@
|
|||||||
unsigned int downloaderImplementsSetPriority:1;
|
unsigned int downloaderImplementsSetPriority:1;
|
||||||
unsigned int downloaderImplementsAnimatedImage:1;
|
unsigned int downloaderImplementsAnimatedImage:1;
|
||||||
unsigned int downloaderImplementsCancelWithResume:1;
|
unsigned int downloaderImplementsCancelWithResume:1;
|
||||||
|
unsigned int downloaderImplementsDownloadWithPriority:1;
|
||||||
} _downloaderFlags;
|
} _downloaderFlags;
|
||||||
|
|
||||||
// Immutable and set on init only. We don't need to lock in this case.
|
// Immutable and set on init only. We don't need to lock in this case.
|
||||||
@ -98,6 +99,7 @@ static std::atomic_bool _useMainThreadDelegateCallbacks(true);
|
|||||||
_downloaderFlags.downloaderImplementsSetPriority = [downloader respondsToSelector:@selector(setPriority:withDownloadIdentifier:)];
|
_downloaderFlags.downloaderImplementsSetPriority = [downloader respondsToSelector:@selector(setPriority:withDownloadIdentifier:)];
|
||||||
_downloaderFlags.downloaderImplementsAnimatedImage = [downloader respondsToSelector:@selector(animatedImageWithData:)];
|
_downloaderFlags.downloaderImplementsAnimatedImage = [downloader respondsToSelector:@selector(animatedImageWithData:)];
|
||||||
_downloaderFlags.downloaderImplementsCancelWithResume = [downloader respondsToSelector:@selector(cancelImageDownloadWithResumePossibilityForIdentifier:)];
|
_downloaderFlags.downloaderImplementsCancelWithResume = [downloader respondsToSelector:@selector(cancelImageDownloadWithResumePossibilityForIdentifier:)];
|
||||||
|
_downloaderFlags.downloaderImplementsDownloadWithPriority = [downloader respondsToSelector:@selector(downloadImageWithURL:priority:callbackQueue:downloadProgress:completion:)];
|
||||||
|
|
||||||
_cacheFlags.cacheSupportsClearing = [cache respondsToSelector:@selector(clearFetchedImageFromCacheWithURL:)];
|
_cacheFlags.cacheSupportsClearing = [cache respondsToSelector:@selector(clearFetchedImageFromCacheWithURL:)];
|
||||||
_cacheFlags.cacheSupportsSynchronousFetch = [cache respondsToSelector:@selector(synchronouslyFetchedCachedImageWithURL:)];
|
_cacheFlags.cacheSupportsSynchronousFetch = [cache respondsToSelector:@selector(synchronouslyFetchedCachedImageWithURL:)];
|
||||||
@ -369,11 +371,8 @@ static std::atomic_bool _useMainThreadDelegateCallbacks(true);
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self.image == nil && _downloaderFlags.downloaderImplementsSetPriority) {
|
if (self.image == nil) {
|
||||||
id downloadIdentifier = ASLockedSelf(_downloadIdentifier);
|
[self _updatePriorityOnDownloaderIfNeededWithDefaultPriority:ASImageDownloaderPriorityImminent];
|
||||||
if (downloadIdentifier != nil) {
|
|
||||||
[_downloader setPriority:ASImageDownloaderPriorityImminent withDownloadIdentifier:downloadIdentifier];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -382,35 +381,25 @@ static std::atomic_bool _useMainThreadDelegateCallbacks(true);
|
|||||||
- (void)didEnterVisibleState
|
- (void)didEnterVisibleState
|
||||||
{
|
{
|
||||||
[super didEnterVisibleState];
|
[super didEnterVisibleState];
|
||||||
|
[self _updatePriorityOnDownloaderIfNeededWithDefaultPriority:ASImageDownloaderPriorityVisible];
|
||||||
id downloadIdentifier = ({
|
|
||||||
ASLockScopeSelf();
|
|
||||||
_downloaderFlags.downloaderImplementsSetPriority ? _downloadIdentifier : nil;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (downloadIdentifier != nil) {
|
|
||||||
[_downloader setPriority:ASImageDownloaderPriorityVisible withDownloadIdentifier:downloadIdentifier];
|
|
||||||
}
|
|
||||||
|
|
||||||
[self _updateProgressImageBlockOnDownloaderIfNeeded];
|
[self _updateProgressImageBlockOnDownloaderIfNeeded];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)didExitVisibleState
|
- (void)didExitVisibleState
|
||||||
{
|
{
|
||||||
[super didExitVisibleState];
|
[super didExitVisibleState];
|
||||||
|
[self _updatePriorityOnDownloaderIfNeededWithDefaultPriority:ASImageDownloaderPriorityPreload];
|
||||||
id downloadIdentifier = ({
|
|
||||||
ASLockScopeSelf();
|
|
||||||
_downloaderFlags.downloaderImplementsSetPriority ? _downloadIdentifier : nil;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (downloadIdentifier != nil) {
|
|
||||||
[_downloader setPriority:ASImageDownloaderPriorityPreload withDownloadIdentifier:downloadIdentifier];
|
|
||||||
}
|
|
||||||
|
|
||||||
[self _updateProgressImageBlockOnDownloaderIfNeeded];
|
[self _updateProgressImageBlockOnDownloaderIfNeeded];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)didExitDisplayState
|
||||||
|
{
|
||||||
|
[super didExitDisplayState];
|
||||||
|
if (ASActivateExperimentalFeature(ASExperimentalImageDownloaderPriority)) {
|
||||||
|
[self _updatePriorityOnDownloaderIfNeededWithDefaultPriority:ASImageDownloaderPriorityPreload];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
- (void)didExitPreloadState
|
- (void)didExitPreloadState
|
||||||
{
|
{
|
||||||
[super didExitPreloadState];
|
[super didExitPreloadState];
|
||||||
@ -457,6 +446,22 @@ static std::atomic_bool _useMainThreadDelegateCallbacks(true);
|
|||||||
[self _locked__setImage:progressImage];
|
[self _locked__setImage:progressImage];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)_updatePriorityOnDownloaderIfNeededWithDefaultPriority:(ASImageDownloaderPriority)defaultPriority
|
||||||
|
{
|
||||||
|
if (_downloaderFlags.downloaderImplementsSetPriority) {
|
||||||
|
ASLockScopeSelf();
|
||||||
|
|
||||||
|
if (_downloadIdentifier != nil) {
|
||||||
|
ASImageDownloaderPriority priority = defaultPriority;
|
||||||
|
if (ASActivateExperimentalFeature(ASExperimentalImageDownloaderPriority)) {
|
||||||
|
priority = ASImageDownloaderPriorityWithInterfaceState(_interfaceState);
|
||||||
|
}
|
||||||
|
|
||||||
|
[_downloader setPriority:priority withDownloadIdentifier:_downloadIdentifier];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
- (void)_updateProgressImageBlockOnDownloaderIfNeeded
|
- (void)_updateProgressImageBlockOnDownloaderIfNeeded
|
||||||
{
|
{
|
||||||
// If the downloader doesn't do progress, we are done.
|
// If the downloader doesn't do progress, we are done.
|
||||||
@ -574,24 +579,55 @@ static std::atomic_bool _useMainThreadDelegateCallbacks(true);
|
|||||||
NSURL *url;
|
NSURL *url;
|
||||||
id downloadIdentifier;
|
id downloadIdentifier;
|
||||||
BOOL cancelAndReattempt = NO;
|
BOOL cancelAndReattempt = NO;
|
||||||
|
ASInterfaceState interfaceState;
|
||||||
|
|
||||||
// Below, to avoid performance issues, we're calling downloadImageWithURL without holding the lock. This is a bit ugly because
|
// Below, to avoid performance issues, we're calling downloadImageWithURL without holding the lock. This is a bit ugly because
|
||||||
// We need to reobtain the lock after and ensure that the task we've kicked off still matches our URL. If not, we need to cancel
|
// We need to reobtain the lock after and ensure that the task we've kicked off still matches our URL. If not, we need to cancel
|
||||||
// it and try again.
|
// it and try again.
|
||||||
{
|
{
|
||||||
ASLockScopeSelf();
|
ASLockScopeSelf();
|
||||||
url = self->_URL;
|
url = self->_URL;
|
||||||
|
interfaceState = self->_interfaceState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dispatch_queue_t callbackQueue = [self callbackQueue];
|
||||||
|
ASImageDownloaderProgress downloadProgress = NULL;
|
||||||
|
ASImageDownloaderCompletion completion = ^(id <ASImageContainerProtocol> _Nullable imageContainer, NSError * _Nullable error, id _Nullable downloadIdentifier, id _Nullable userInfo) {
|
||||||
|
if (finished != NULL) {
|
||||||
|
finished(imageContainer, error, downloadIdentifier, userInfo);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
downloadIdentifier = [self->_downloader downloadImageWithURL:url
|
if (self->_downloaderFlags.downloaderImplementsDownloadWithPriority
|
||||||
callbackQueue:[self callbackQueue]
|
&& ASActivateExperimentalFeature(ASExperimentalImageDownloaderPriority)) {
|
||||||
downloadProgress:NULL
|
/*
|
||||||
completion:^(id <ASImageContainerProtocol> _Nullable imageContainer, NSError * _Nullable error, id _Nullable downloadIdentifier, id _Nullable userInfo) {
|
Decide a priority based on the current interface state of this node.
|
||||||
if (finished != NULL) {
|
It can happen that this method was called when the node entered preload state
|
||||||
finished(imageContainer, error, downloadIdentifier, userInfo);
|
but the interface state, at this point, tells us that the node is (going to be) visible.
|
||||||
}
|
If that's the case, we jump to a higher priority directly.
|
||||||
}];
|
*/
|
||||||
|
ASImageDownloaderPriority priority = ASImageDownloaderPriorityWithInterfaceState(interfaceState);
|
||||||
|
|
||||||
|
downloadIdentifier = [self->_downloader downloadImageWithURL:url
|
||||||
|
priority:priority
|
||||||
|
callbackQueue:callbackQueue
|
||||||
|
downloadProgress:downloadProgress
|
||||||
|
completion:completion];
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
Kick off a download with default priority.
|
||||||
|
The actual "default" value is decided by the downloader.
|
||||||
|
ASBasicImageDownloader and ASPINRemoteImageDownloader both use ASImageDownloaderPriorityImminent
|
||||||
|
which is mapped to NSURLSessionTaskPriorityDefault.
|
||||||
|
|
||||||
|
This means that preload and display nodes use the same priority
|
||||||
|
and their requests are put into the same pool.
|
||||||
|
*/
|
||||||
|
downloadIdentifier = [self->_downloader downloadImageWithURL:url
|
||||||
|
callbackQueue:callbackQueue
|
||||||
|
downloadProgress:downloadProgress
|
||||||
|
completion:completion];
|
||||||
|
}
|
||||||
as_log_verbose(ASImageLoadingLog(), "Downloading image for %@ url: %@", self, url);
|
as_log_verbose(ASImageLoadingLog(), "Downloading image for %@ url: %@", self, url);
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#import <AsyncDisplayKit/ASBasicImageDownloader.h>
|
#import <AsyncDisplayKit/ASBasicImageDownloader.h>
|
||||||
|
|
||||||
|
#import <Foundation/NSURLSession.h>
|
||||||
#import <objc/runtime.h>
|
#import <objc/runtime.h>
|
||||||
|
|
||||||
#import <AsyncDisplayKit/ASBasicImageDownloaderInternal.h>
|
#import <AsyncDisplayKit/ASBasicImageDownloaderInternal.h>
|
||||||
@ -25,6 +26,19 @@ NSString * const kASBasicImageDownloaderContextCallbackQueue = @"kASBasicImageDo
|
|||||||
NSString * const kASBasicImageDownloaderContextProgressBlock = @"kASBasicImageDownloaderContextProgressBlock";
|
NSString * const kASBasicImageDownloaderContextProgressBlock = @"kASBasicImageDownloaderContextProgressBlock";
|
||||||
NSString * const kASBasicImageDownloaderContextCompletionBlock = @"kASBasicImageDownloaderContextCompletionBlock";
|
NSString * const kASBasicImageDownloaderContextCompletionBlock = @"kASBasicImageDownloaderContextCompletionBlock";
|
||||||
|
|
||||||
|
static inline float NSURLSessionTaskPriorityWithImageDownloaderPriority(ASImageDownloaderPriority priority) {
|
||||||
|
switch (priority) {
|
||||||
|
case ASImageDownloaderPriorityPreload:
|
||||||
|
return NSURLSessionTaskPriorityLow;
|
||||||
|
|
||||||
|
case ASImageDownloaderPriorityImminent:
|
||||||
|
return NSURLSessionTaskPriorityDefault;
|
||||||
|
|
||||||
|
case ASImageDownloaderPriorityVisible:
|
||||||
|
return NSURLSessionTaskPriorityHigh;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@interface ASBasicImageDownloaderContext ()
|
@interface ASBasicImageDownloaderContext ()
|
||||||
{
|
{
|
||||||
BOOL _invalid;
|
BOOL _invalid;
|
||||||
@ -238,10 +252,23 @@ static const void *ContextKey() {
|
|||||||
|
|
||||||
#pragma mark ASImageDownloaderProtocol.
|
#pragma mark ASImageDownloaderProtocol.
|
||||||
|
|
||||||
- (id)downloadImageWithURL:(NSURL *)URL
|
- (nullable id)downloadImageWithURL:(NSURL *)URL
|
||||||
callbackQueue:(dispatch_queue_t)callbackQueue
|
callbackQueue:(dispatch_queue_t)callbackQueue
|
||||||
downloadProgress:(nullable ASImageDownloaderProgress)downloadProgress
|
downloadProgress:(nullable ASImageDownloaderProgress)downloadProgress
|
||||||
completion:(ASImageDownloaderCompletion)completion
|
completion:(ASImageDownloaderCompletion)completion
|
||||||
|
{
|
||||||
|
return [self downloadImageWithURL:URL
|
||||||
|
priority:ASImageDownloaderPriorityImminent // maps to default priority
|
||||||
|
callbackQueue:callbackQueue
|
||||||
|
downloadProgress:downloadProgress
|
||||||
|
completion:completion];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (nullable id)downloadImageWithURL:(NSURL *)URL
|
||||||
|
priority:(ASImageDownloaderPriority)priority
|
||||||
|
callbackQueue:(dispatch_queue_t)callbackQueue
|
||||||
|
downloadProgress:(ASImageDownloaderProgress)downloadProgress
|
||||||
|
completion:(ASImageDownloaderCompletion)completion
|
||||||
{
|
{
|
||||||
ASBasicImageDownloaderContext *context = [ASBasicImageDownloaderContext contextForURL:URL];
|
ASBasicImageDownloaderContext *context = [ASBasicImageDownloaderContext contextForURL:URL];
|
||||||
|
|
||||||
@ -266,6 +293,7 @@ static const void *ContextKey() {
|
|||||||
NSURLSessionDownloadTask *task = (NSURLSessionDownloadTask *)[context createSessionTaskIfNecessaryWithBlock:^(){return [_session downloadTaskWithURL:URL];}];
|
NSURLSessionDownloadTask *task = (NSURLSessionDownloadTask *)[context createSessionTaskIfNecessaryWithBlock:^(){return [_session downloadTaskWithURL:URL];}];
|
||||||
|
|
||||||
if (task) {
|
if (task) {
|
||||||
|
task.priority = NSURLSessionTaskPriorityWithImageDownloaderPriority(priority);
|
||||||
task.originalRequest.asyncdisplaykit_context = context;
|
task.originalRequest.asyncdisplaykit_context = context;
|
||||||
|
|
||||||
// start downloading
|
// start downloading
|
||||||
|
@ -102,17 +102,35 @@ typedef NS_ENUM(NSUInteger, ASImageDownloaderPriority) {
|
|||||||
/**
|
/**
|
||||||
@abstract Cancels an image download.
|
@abstract Cancels an image download.
|
||||||
@param downloadIdentifier The opaque download identifier object returned from
|
@param downloadIdentifier The opaque download identifier object returned from
|
||||||
`downloadImageWithURL:callbackQueue:downloadProgressBlock:completion:`.
|
`downloadImageWithURL:callbackQueue:downloadProgress:completion:`.
|
||||||
@discussion This method has no effect if `downloadIdentifier` is nil.
|
@discussion This method has no effect if `downloadIdentifier` is nil.
|
||||||
*/
|
*/
|
||||||
- (void)cancelImageDownloadForIdentifier:(id)downloadIdentifier;
|
- (void)cancelImageDownloadForIdentifier:(id)downloadIdentifier;
|
||||||
|
|
||||||
@optional
|
@optional
|
||||||
|
|
||||||
|
/**
|
||||||
|
@abstract Downloads an image with the given URL.
|
||||||
|
@param URL The URL of the image to download.
|
||||||
|
@param priority The priority at which the image should be downloaded.
|
||||||
|
@param callbackQueue The queue to call `downloadProgressBlock` and `completion` on.
|
||||||
|
@param downloadProgress The block to be invoked when the download of `URL` progresses.
|
||||||
|
@param completion The block to be invoked when the download has completed, or has failed.
|
||||||
|
@discussion This method is likely to be called on the main thread, so any custom implementations should make sure to background any expensive download operations.
|
||||||
|
@note If this method is implemented, it will be called instead of the required method (`downloadImageWithURL:callbackQueue:downloadProgress:completion:`).
|
||||||
|
@result An opaque identifier to be used in canceling the download, via `cancelImageDownloadForIdentifier:`. You must
|
||||||
|
retain the identifier if you wish to use it later.
|
||||||
|
*/
|
||||||
|
- (nullable id)downloadImageWithURL:(NSURL *)URL
|
||||||
|
priority:(ASImageDownloaderPriority)priority
|
||||||
|
callbackQueue:(dispatch_queue_t)callbackQueue
|
||||||
|
downloadProgress:(nullable ASImageDownloaderProgress)downloadProgress
|
||||||
|
completion:(ASImageDownloaderCompletion)completion;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@abstract Cancels an image download, however indicating resume data should be stored in case of redownload.
|
@abstract Cancels an image download, however indicating resume data should be stored in case of redownload.
|
||||||
@param downloadIdentifier The opaque download identifier object returned from
|
@param downloadIdentifier The opaque download identifier object returned from
|
||||||
`downloadImageWithURL:callbackQueue:downloadProgressBlock:completion:`.
|
`downloadImageWithURL:callbackQueue:downloadProgress:completion:`.
|
||||||
@discussion This method has no effect if `downloadIdentifier` is nil. If implemented, this method
|
@discussion This method has no effect if `downloadIdentifier` is nil. If implemented, this method
|
||||||
may be called instead of `cancelImageDownloadForIdentifier:` in cases where ASDK believes there's a chance
|
may be called instead of `cancelImageDownloadForIdentifier:` in cases where ASDK believes there's a chance
|
||||||
the image download will be resumed (currently when an image exits preload range). You can use this to store
|
the image download will be resumed (currently when an image exits preload range). You can use this to store
|
||||||
@ -130,7 +148,7 @@ typedef NS_ENUM(NSUInteger, ASImageDownloaderPriority) {
|
|||||||
/**
|
/**
|
||||||
@abstract Sets block to be called when a progress image is available.
|
@abstract Sets block to be called when a progress image is available.
|
||||||
@param progressBlock The block to be invoked when the download has a progressive render of an image available.
|
@param progressBlock The block to be invoked when the download has a progressive render of an image available.
|
||||||
@param callbackQueue The queue to call `progressBlock` on.
|
@param callbackQueue The queue to call `progressImageBlock` on.
|
||||||
@param downloadIdentifier The opaque download identifier object returned from
|
@param downloadIdentifier The opaque download identifier object returned from
|
||||||
`downloadImageWithURL:callbackQueue:downloadProgressBlock:completion:`.
|
`downloadImageWithURL:callbackQueue:downloadProgressBlock:completion:`.
|
||||||
*/
|
*/
|
||||||
|
@ -34,6 +34,19 @@
|
|||||||
#import <PINRemoteImage/NSData+ImageDetectors.h>
|
#import <PINRemoteImage/NSData+ImageDetectors.h>
|
||||||
#import <PINRemoteImage/PINRemoteImageCaching.h>
|
#import <PINRemoteImage/PINRemoteImageCaching.h>
|
||||||
|
|
||||||
|
static inline PINRemoteImageManagerPriority PINRemoteImageManagerPriorityWithASImageDownloaderPriority(ASImageDownloaderPriority priority) {
|
||||||
|
switch (priority) {
|
||||||
|
case ASImageDownloaderPriorityPreload:
|
||||||
|
return PINRemoteImageManagerPriorityLow;
|
||||||
|
|
||||||
|
case ASImageDownloaderPriorityImminent:
|
||||||
|
return PINRemoteImageManagerPriorityDefault;
|
||||||
|
|
||||||
|
case ASImageDownloaderPriorityVisible:
|
||||||
|
return PINRemoteImageManagerPriorityHigh;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#if PIN_ANIMATED_AVAILABLE
|
#if PIN_ANIMATED_AVAILABLE
|
||||||
|
|
||||||
@interface ASPINRemoteImageDownloader () <PINRemoteImageManagerAlternateRepresentationProvider>
|
@interface ASPINRemoteImageDownloader () <PINRemoteImageManagerAlternateRepresentationProvider>
|
||||||
@ -245,6 +258,21 @@ static dispatch_once_t shared_init_predicate;
|
|||||||
downloadProgress:(ASImageDownloaderProgress)downloadProgress
|
downloadProgress:(ASImageDownloaderProgress)downloadProgress
|
||||||
completion:(ASImageDownloaderCompletion)completion;
|
completion:(ASImageDownloaderCompletion)completion;
|
||||||
{
|
{
|
||||||
|
return [self downloadImageWithURL:URL
|
||||||
|
priority:ASImageDownloaderPriorityImminent // maps to default priority
|
||||||
|
callbackQueue:callbackQueue
|
||||||
|
downloadProgress:downloadProgress
|
||||||
|
completion:completion];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (nullable id)downloadImageWithURL:(NSURL *)URL
|
||||||
|
priority:(ASImageDownloaderPriority)priority
|
||||||
|
callbackQueue:(dispatch_queue_t)callbackQueue
|
||||||
|
downloadProgress:(ASImageDownloaderProgress)downloadProgress
|
||||||
|
completion:(ASImageDownloaderCompletion)completion
|
||||||
|
{
|
||||||
|
PINRemoteImageManagerPriority pi_priority = PINRemoteImageManagerPriorityWithASImageDownloaderPriority(priority);
|
||||||
|
|
||||||
PINRemoteImageManagerProgressDownload progressDownload = ^(int64_t completedBytes, int64_t totalBytes) {
|
PINRemoteImageManagerProgressDownload progressDownload = ^(int64_t completedBytes, int64_t totalBytes) {
|
||||||
if (downloadProgress == nil) { return; }
|
if (downloadProgress == nil) { return; }
|
||||||
|
|
||||||
@ -274,6 +302,7 @@ static dispatch_once_t shared_init_predicate;
|
|||||||
// check the cache as part of this download.
|
// check the cache as part of this download.
|
||||||
return [[self sharedPINRemoteImageManager] downloadImageWithURL:URL
|
return [[self sharedPINRemoteImageManager] downloadImageWithURL:URL
|
||||||
options:PINRemoteImageManagerDownloadOptionsSkipDecode | PINRemoteImageManagerDownloadOptionsIgnoreCache
|
options:PINRemoteImageManagerDownloadOptionsSkipDecode | PINRemoteImageManagerDownloadOptionsIgnoreCache
|
||||||
|
priority:pi_priority
|
||||||
progressImage:nil
|
progressImage:nil
|
||||||
progressDownload:progressDownload
|
progressDownload:progressDownload
|
||||||
completion:imageCompletion];
|
completion:imageCompletion];
|
||||||
@ -310,20 +339,7 @@ static dispatch_once_t shared_init_predicate;
|
|||||||
{
|
{
|
||||||
ASDisplayNodeAssert([downloadIdentifier isKindOfClass:[NSUUID class]], @"downloadIdentifier must be NSUUID");
|
ASDisplayNodeAssert([downloadIdentifier isKindOfClass:[NSUUID class]], @"downloadIdentifier must be NSUUID");
|
||||||
|
|
||||||
PINRemoteImageManagerPriority pi_priority = PINRemoteImageManagerPriorityDefault;
|
PINRemoteImageManagerPriority pi_priority = PINRemoteImageManagerPriorityWithASImageDownloaderPriority(priority);
|
||||||
switch (priority) {
|
|
||||||
case ASImageDownloaderPriorityPreload:
|
|
||||||
pi_priority = PINRemoteImageManagerPriorityLow;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ASImageDownloaderPriorityImminent:
|
|
||||||
pi_priority = PINRemoteImageManagerPriorityDefault;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ASImageDownloaderPriorityVisible:
|
|
||||||
pi_priority = PINRemoteImageManagerPriorityHigh;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
[[self sharedPINRemoteImageManager] setPriority:pi_priority ofTaskWithUUID:downloadIdentifier];
|
[[self sharedPINRemoteImageManager] setPriority:pi_priority ofTaskWithUUID:downloadIdentifier];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,6 +12,8 @@
|
|||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
#import <AsyncDisplayKit/ASBaseDefines.h>
|
#import <AsyncDisplayKit/ASBaseDefines.h>
|
||||||
|
#import <AsyncDisplayKit/ASDisplayNodeExtras.h>
|
||||||
|
#import <AsyncDisplayKit/ASImageProtocols.h>
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
@ -95,6 +97,22 @@ ASDISPLAYNODE_INLINE UIEdgeInsets ASConcatInsets(UIEdgeInsets insetsA, UIEdgeIns
|
|||||||
return insetsA;
|
return insetsA;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ASDISPLAYNODE_INLINE AS_WARN_UNUSED_RESULT ASImageDownloaderPriority ASImageDownloaderPriorityWithInterfaceState(ASInterfaceState interfaceState) {
|
||||||
|
if (ASInterfaceStateIncludesVisible(interfaceState)) {
|
||||||
|
return ASImageDownloaderPriorityVisible;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ASInterfaceStateIncludesDisplay(interfaceState)) {
|
||||||
|
return ASImageDownloaderPriorityImminent;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ASInterfaceStateIncludesPreload(interfaceState)) {
|
||||||
|
return ASImageDownloaderPriorityPreload;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ASImageDownloaderPriorityPreload;
|
||||||
|
}
|
||||||
|
|
||||||
@interface NSIndexPath (ASInverseComparison)
|
@interface NSIndexPath (ASInverseComparison)
|
||||||
- (NSComparisonResult)asdk_inverseCompare:(NSIndexPath *)otherIndexPath;
|
- (NSComparisonResult)asdk_inverseCompare:(NSIndexPath *)otherIndexPath;
|
||||||
@end
|
@end
|
||||||
|
@ -30,7 +30,8 @@ static ASExperimentalFeatures features[] = {
|
|||||||
ASExperimentalDisableAccessibilityCache,
|
ASExperimentalDisableAccessibilityCache,
|
||||||
ASExperimentalSkipAccessibilityWait,
|
ASExperimentalSkipAccessibilityWait,
|
||||||
ASExperimentalNewDefaultCellLayoutMode,
|
ASExperimentalNewDefaultCellLayoutMode,
|
||||||
ASExperimentalDispatchApply
|
ASExperimentalDispatchApply,
|
||||||
|
ASExperimentalImageDownloaderPriority
|
||||||
};
|
};
|
||||||
|
|
||||||
@interface ASConfigurationTests : ASTestCase <ASConfigurationDelegate>
|
@interface ASConfigurationTests : ASTestCase <ASConfigurationDelegate>
|
||||||
@ -55,7 +56,8 @@ static ASExperimentalFeatures features[] = {
|
|||||||
@"exp_disable_a11y_cache",
|
@"exp_disable_a11y_cache",
|
||||||
@"exp_skip_a11y_wait",
|
@"exp_skip_a11y_wait",
|
||||||
@"exp_new_default_cell_layout_mode",
|
@"exp_new_default_cell_layout_mode",
|
||||||
@"exp_dispatch_apply"
|
@"exp_dispatch_apply",
|
||||||
|
@"exp_image_downloader_priority"
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user