mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-17 20:00:38 +00:00
Merge remote-tracking branch 'facebook/master' into ASVideoPlayerNode
This commit is contained in:
commit
b09d0dca9e
@ -125,6 +125,10 @@
|
||||
{
|
||||
CGSize oldSize = self.calculatedSize;
|
||||
[super __setNeedsLayout];
|
||||
|
||||
//Adding this lock because lock used to be held when this method was called. Not sure if it's necessary for
|
||||
//didRelayoutFromOldSize:toNewSize:
|
||||
ASDN::MutexLocker l(_propertyLock);
|
||||
[self didRelayoutFromOldSize:oldSize toNewSize:self.calculatedSize];
|
||||
}
|
||||
|
||||
|
||||
@ -373,7 +373,6 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
|
||||
_pendingViewState = nil;
|
||||
|
||||
_displaySentinel = nil;
|
||||
_transitionSentinel = nil;
|
||||
|
||||
_pendingDisplayNodes = nil;
|
||||
}
|
||||
@ -654,6 +653,8 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
|
||||
return (!_flags.isMeasured || !ASSizeRangeEqualToSizeRange(constrainedSize, _constrainedSize));
|
||||
}
|
||||
|
||||
#pragma mark - Layout Transition
|
||||
|
||||
- (void)transitionLayoutWithAnimation:(BOOL)animated
|
||||
shouldMeasureAsync:(BOOL)shouldMeasureAsync
|
||||
measurementCompletion:(void(^)())completion
|
||||
@ -681,10 +682,10 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
|
||||
ASDisplayNodeAssert(ASHierarchyStateIncludesLayoutPending(_hierarchyState) == NO, @"Can't start a transition when one of the supernodes is performing one.");
|
||||
}
|
||||
|
||||
int32_t transitionID = [self _newTransitionID];
|
||||
int32_t transitionID = [self _startNewTransition];
|
||||
|
||||
ASDisplayNodePerformBlockOnEverySubnode(self, ^(ASDisplayNode * _Nonnull node) {
|
||||
ASDisplayNodeAssert([node _hasTransitionsInProgress] == NO, @"Can't start a transition when one of the subnodes is performing one.");
|
||||
ASDisplayNodeAssert([node _hasTransitionInProgress] == NO, @"Can't start a transition when one of the subnodes is performing one.");
|
||||
node.hierarchyState |= ASHierarchyStateLayoutPending;
|
||||
node.pendingTransitionID = transitionID;
|
||||
});
|
||||
@ -726,13 +727,13 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
|
||||
ASSizeRange previousConstrainedSize = _constrainedSize;
|
||||
[self applyLayout:newLayout constrainedSize:constrainedSize layoutContext:nil];
|
||||
|
||||
[self _invalidateTransitionSentinel];
|
||||
|
||||
ASDisplayNodePerformBlockOnEverySubnode(self, ^(ASDisplayNode * _Nonnull node) {
|
||||
[node applyPendingLayoutContext];
|
||||
[node _completeLayoutCalculation];
|
||||
node.hierarchyState &= (~ASHierarchyStateLayoutPending);
|
||||
});
|
||||
|
||||
[self _finishOrCancelTransition];
|
||||
|
||||
if (completion) {
|
||||
completion();
|
||||
@ -781,7 +782,6 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void)calculatedLayoutDidChange
|
||||
{
|
||||
// subclass override
|
||||
@ -790,9 +790,10 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
|
||||
- (void)cancelLayoutTransitionsInProgress
|
||||
{
|
||||
ASDN::MutexLocker l(_propertyLock);
|
||||
if ([self _hasTransitionsInProgress]) {
|
||||
// Invalidate transition sentinel to cancel transitions in progress
|
||||
[self _invalidateTransitionSentinel];
|
||||
if ([self _hasTransitionInProgress]) {
|
||||
// Cancel transition in progress
|
||||
[self _finishOrCancelTransition];
|
||||
|
||||
// Tell subnodes to exit layout pending state and clear related properties
|
||||
ASDisplayNodePerformBlockOnEverySubnode(self, ^(ASDisplayNode * _Nonnull node) {
|
||||
node.hierarchyState &= (~ASHierarchyStateLayoutPending);
|
||||
@ -800,8 +801,6 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Layout Transition
|
||||
|
||||
- (BOOL)usesImplicitHierarchyManagement
|
||||
{
|
||||
ASDN::MutexLocker l(_propertyLock);
|
||||
@ -814,6 +813,33 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
|
||||
_usesImplicitHierarchyManagement = value;
|
||||
}
|
||||
|
||||
- (BOOL)_hasTransitionInProgress
|
||||
{
|
||||
ASDN::MutexLocker l(_propertyLock);
|
||||
return _transitionInProgress;
|
||||
}
|
||||
|
||||
/// Starts a new transition and returns the transition id
|
||||
- (int32_t)_startNewTransition
|
||||
{
|
||||
ASDN::MutexLocker l(_propertyLock);
|
||||
_transitionInProgress = YES;
|
||||
_transitionID = OSAtomicAdd32(1, &_transitionID);
|
||||
return _transitionID;
|
||||
}
|
||||
|
||||
- (void)_finishOrCancelTransition
|
||||
{
|
||||
ASDN::MutexLocker l(_propertyLock);
|
||||
_transitionInProgress = NO;
|
||||
}
|
||||
|
||||
- (BOOL)_shouldAbortTransitionWithID:(int32_t)transitionID
|
||||
{
|
||||
ASDN::MutexLocker l(_propertyLock);
|
||||
return (!_transitionInProgress || _transitionID != transitionID);
|
||||
}
|
||||
|
||||
- (void)animateLayoutTransition:(id<ASContextTransitioning>)context
|
||||
{
|
||||
[self __layoutSublayouts];
|
||||
@ -827,6 +853,7 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
|
||||
_pendingLayoutContext = nil;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - _ASTransitionContextCompletionDelegate
|
||||
|
||||
- (void)transitionContext:(_ASTransitionContext *)context didComplete:(BOOL)didComplete
|
||||
@ -1001,27 +1028,31 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
|
||||
[self invalidateCalculatedLayout];
|
||||
|
||||
if (_supernode) {
|
||||
ASDisplayNode *supernode = _supernode;
|
||||
ASDN::MutexUnlocker u(_propertyLock);
|
||||
// Cause supernode's layout to be invalidated
|
||||
[_supernode setNeedsLayout];
|
||||
} else {
|
||||
// This is the root node. Trigger a full measurement pass on *current* thread. Old constrained size is re-used.
|
||||
[self measureWithSizeRange:oldConstrainedSize];
|
||||
// We need to release the lock to prevent a deadlock
|
||||
[supernode setNeedsLayout];
|
||||
return;
|
||||
}
|
||||
|
||||
// This is the root node. Trigger a full measurement pass on *current* thread. Old constrained size is re-used.
|
||||
[self measureWithSizeRange:oldConstrainedSize];
|
||||
|
||||
CGRect oldBounds = self.bounds;
|
||||
CGSize oldSize = oldBounds.size;
|
||||
CGSize newSize = _layout.size;
|
||||
CGRect oldBounds = self.bounds;
|
||||
CGSize oldSize = oldBounds.size;
|
||||
CGSize newSize = _layout.size;
|
||||
|
||||
if (! CGSizeEqualToSize(oldSize, newSize)) {
|
||||
self.bounds = (CGRect){ oldBounds.origin, newSize };
|
||||
|
||||
if (! CGSizeEqualToSize(oldSize, newSize)) {
|
||||
self.bounds = (CGRect){ oldBounds.origin, newSize };
|
||||
|
||||
// Frame's origin must be preserved. Since it is computed from bounds size, anchorPoint
|
||||
// and position (see frame setter in ASDisplayNode+UIViewBridge), position needs to be adjusted.
|
||||
CGPoint anchorPoint = self.anchorPoint;
|
||||
CGPoint oldPosition = self.position;
|
||||
CGFloat xDelta = (newSize.width - oldSize.width) * anchorPoint.x;
|
||||
CGFloat yDelta = (newSize.height - oldSize.height) * anchorPoint.y;
|
||||
self.position = CGPointMake(oldPosition.x + xDelta, oldPosition.y + yDelta);
|
||||
}
|
||||
// Frame's origin must be preserved. Since it is computed from bounds size, anchorPoint
|
||||
// and position (see frame setter in ASDisplayNode+UIViewBridge), position needs to be adjusted.
|
||||
CGPoint anchorPoint = self.anchorPoint;
|
||||
CGPoint oldPosition = self.position;
|
||||
CGFloat xDelta = (newSize.width - oldSize.width) * anchorPoint.x;
|
||||
CGFloat yDelta = (newSize.height - oldSize.height) * anchorPoint.y;
|
||||
self.position = CGPointMake(oldPosition.x + xDelta, oldPosition.y + yDelta);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1685,9 +1716,11 @@ static NSInteger incrementIfFound(NSInteger i) {
|
||||
}
|
||||
|
||||
if (supernodeDidChange) {
|
||||
// Hierarchy state
|
||||
ASHierarchyState stateToEnterOrExit = (newSupernode ? newSupernode.hierarchyState
|
||||
: oldSupernode.hierarchyState);
|
||||
|
||||
// Rasterized state
|
||||
BOOL parentWasOrIsRasterized = (newSupernode ? newSupernode.shouldRasterizeDescendants
|
||||
: oldSupernode.shouldRasterizeDescendants);
|
||||
if (parentWasOrIsRasterized) {
|
||||
@ -1696,6 +1729,10 @@ static NSInteger incrementIfFound(NSInteger i) {
|
||||
if (newSupernode) {
|
||||
[self enterHierarchyState:stateToEnterOrExit];
|
||||
} else {
|
||||
// If a node will be removed from the supernode it should go out from the layout pending state to remove all
|
||||
// layout pending state related properties on the node
|
||||
stateToEnterOrExit |= ASHierarchyStateLayoutPending;
|
||||
|
||||
[self exitHierarchyState:stateToEnterOrExit];
|
||||
}
|
||||
}
|
||||
@ -2640,38 +2677,12 @@ static const char *ASDisplayNodeDrawingPriorityKey = "ASDrawingPriority";
|
||||
_flags.isInHierarchy = inHierarchy;
|
||||
}
|
||||
|
||||
- (BOOL)_hasTransitionsInProgress
|
||||
{
|
||||
ASDN::MutexLocker l(_propertyLock);
|
||||
return _transitionSentinel != nil;
|
||||
}
|
||||
|
||||
- (void)_invalidateTransitionSentinel
|
||||
{
|
||||
ASDN::MutexLocker l(_propertyLock);
|
||||
_transitionSentinel = nil;
|
||||
}
|
||||
|
||||
- (BOOL)_shouldAbortTransitionWithID:(int32_t)transitionID
|
||||
{
|
||||
ASDN::MutexLocker l(_propertyLock);
|
||||
return _transitionSentinel == nil || transitionID != _transitionSentinel.value;
|
||||
}
|
||||
|
||||
- (int32_t)_newTransitionID
|
||||
{
|
||||
ASDN::MutexLocker l(_propertyLock);
|
||||
if (!_transitionSentinel) {
|
||||
_transitionSentinel = [[ASSentinel alloc] init];
|
||||
}
|
||||
return [_transitionSentinel increment];
|
||||
}
|
||||
|
||||
- (id<ASLayoutable>)finalLayoutable
|
||||
{
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - ASEnvironment
|
||||
|
||||
- (ASEnvironmentState)environmentState
|
||||
|
||||
@ -117,13 +117,20 @@ typedef NS_ENUM(NSUInteger, ASMultiplexImageNodeErrorCode) {
|
||||
*/
|
||||
@property (nullable, nonatomic, readonly) ASImageIdentifier displayedImageIdentifier;
|
||||
|
||||
/**
|
||||
* @abstract If the downloader implements progressive image rendering and this value is YES progressive renders of the
|
||||
* image will be displayed as the image downloads. Regardless of this properties value, progress renders will
|
||||
* only occur when the node is visible. Defaults to YES.
|
||||
*/
|
||||
@property (nonatomic, assign, readwrite) BOOL shouldRenderProgressImages;
|
||||
|
||||
#if TARGET_OS_IOS
|
||||
/**
|
||||
* @abstract The image manager that this image node should use when requesting images from the Photos framework. If this is `nil` (the default), then `PHImageManager.defaultManager` is used.
|
||||
|
||||
* @see `+[NSURL URLWithAssetLocalIdentifier:targetSize:contentMode:options:]` below.
|
||||
*/
|
||||
@property (nonatomic, strong) PHImageManager *imageManager;
|
||||
@property (nullable, nonatomic, strong) PHImageManager *imageManager;
|
||||
#endif
|
||||
@end
|
||||
|
||||
|
||||
@ -85,6 +85,10 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent
|
||||
ASDN::RecursiveMutex _downloadIdentifierLock;
|
||||
id _downloadIdentifier;
|
||||
|
||||
// Properties
|
||||
ASDN::RecursiveMutex _propertyLock;
|
||||
BOOL _shouldRenderProgressImages;
|
||||
|
||||
//set on init only
|
||||
BOOL _downloaderSupportsNewProtocol;
|
||||
BOOL _downloaderImplementsSetProgress;
|
||||
@ -186,6 +190,8 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent
|
||||
_cacheSupportsNewProtocol = [cache respondsToSelector:@selector(cachedImageWithURL:callbackQueue:completion:)];
|
||||
_cacheSupportsClearing = [cache respondsToSelector:@selector(clearFetchedImageFromCacheWithURL:)];
|
||||
|
||||
_shouldRenderProgressImages = YES;
|
||||
|
||||
self.shouldBypassEnsureDisplay = YES;
|
||||
|
||||
return self;
|
||||
@ -339,6 +345,27 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
- (void)setShouldRenderProgressImages:(BOOL)shouldRenderProgressImages
|
||||
{
|
||||
ASDN::MutexLocker l(_propertyLock);
|
||||
if (shouldRenderProgressImages == _shouldRenderProgressImages) {
|
||||
return;
|
||||
}
|
||||
|
||||
_shouldRenderProgressImages = shouldRenderProgressImages;
|
||||
|
||||
|
||||
ASDN::MutexUnlocker u(_propertyLock);
|
||||
[self _updateProgressImageBlockOnDownloaderIfNeeded];
|
||||
}
|
||||
|
||||
- (BOOL)shouldRenderProgressImages
|
||||
{
|
||||
ASDN::MutexLocker l(_propertyLock);
|
||||
return _shouldRenderProgressImages;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
#pragma mark -
|
||||
@ -436,8 +463,12 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent
|
||||
}
|
||||
|
||||
// Grab the best available image from the data source.
|
||||
UIImage *existingImage = self.image;
|
||||
for (id imageIdentifier in _imageIdentifiers) {
|
||||
UIImage *image = [_dataSource multiplexImageNode:self imageForImageIdentifier:imageIdentifier];
|
||||
// If this image is already loaded, don't request it from the data source again because
|
||||
// the data source may generate a new instance of UIImage that returns NO for isEqual:
|
||||
// and we'll end up in an infinite loading loop.
|
||||
UIImage *image = ASObjectIsEqual(imageIdentifier, _loadedImageIdentifier) ? existingImage : [_dataSource multiplexImageNode:self imageForImageIdentifier:imageIdentifier];
|
||||
if (image) {
|
||||
if (imageIdentifierOut) {
|
||||
*imageIdentifierOut = imageIdentifier;
|
||||
@ -458,32 +489,34 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent
|
||||
*/
|
||||
- (void)_updateProgressImageBlockOnDownloaderIfNeeded
|
||||
{
|
||||
// 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 (!_downloaderImplementsSetProgress || _downloadIdentifier == nil) {
|
||||
BOOL shouldRenderProgressImages = self.shouldRenderProgressImages;
|
||||
|
||||
// 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 (!_downloaderImplementsSetProgress || _downloadIdentifier == nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
ASImageDownloaderProgressImage progress = nil;
|
||||
if (shouldRenderProgressImages && ASInterfaceStateIncludesVisible(interfaceState)) {
|
||||
__weak __typeof__(self) weakSelf = self;
|
||||
progress = ^(UIImage * _Nonnull progressImage, CGFloat progress, id _Nullable downloadIdentifier) {
|
||||
__typeof__(self) strongSelf = weakSelf;
|
||||
if (strongSelf == nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
ASImageDownloaderProgressImage progress = nil;
|
||||
if (ASInterfaceStateIncludesVisible(interfaceState)) {
|
||||
__weak __typeof__(self) weakSelf = self;
|
||||
progress = ^(UIImage * _Nonnull progressImage, CGFloat progress, id _Nullable downloadIdentifier) {
|
||||
__typeof__(self) strongSelf = weakSelf;
|
||||
if (strongSelf == nil) {
|
||||
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;
|
||||
}
|
||||
strongSelf.image = progressImage;
|
||||
};
|
||||
}
|
||||
[_downloader setProgressImageBlock:progress callbackQueue:dispatch_get_main_queue() withDownloadIdentifier:_downloadIdentifier];
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
strongSelf.image = progressImage;
|
||||
};
|
||||
}
|
||||
[_downloader setProgressImageBlock:progress callbackQueue:dispatch_get_main_queue() withDownloadIdentifier:_downloadIdentifier];
|
||||
}
|
||||
|
||||
- (void)_clearImage
|
||||
|
||||
@ -73,6 +73,13 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
*/
|
||||
@property (nonatomic, assign, readwrite) BOOL shouldCacheImage;
|
||||
|
||||
/**
|
||||
* If the downloader implements progressive image rendering and this value is YES progressive renders of the
|
||||
* image will be displayed as the image downloads. Regardless of this properties value, progress renders will
|
||||
* only occur when the node is visible. Defaults to YES.
|
||||
*/
|
||||
@property (nonatomic, assign, readwrite) BOOL shouldRenderProgressImages;
|
||||
|
||||
/**
|
||||
* The image quality of the current image. This is a number between 0 and 1 and can be used to track
|
||||
* progressive progress. Calculated by dividing number of bytes / expected number of total bytes.
|
||||
|
||||
@ -45,6 +45,8 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
|
||||
BOOL _delegateSupportsDidStartFetchingData;
|
||||
BOOL _delegateSupportsDidFailWithError;
|
||||
BOOL _delegateSupportsImageNodeDidFinishDecoding;
|
||||
|
||||
BOOL _shouldRenderProgressImages;
|
||||
|
||||
//set on init only
|
||||
BOOL _downloaderSupportsNewProtocol;
|
||||
@ -83,6 +85,7 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
|
||||
_cacheSupportsSynchronousFetch = [cache respondsToSelector:@selector(synchronouslyFetchedCachedImageWithURL:)];
|
||||
|
||||
_shouldCacheImage = YES;
|
||||
_shouldRenderProgressImages = YES;
|
||||
self.shouldBypassEnsureDisplay = YES;
|
||||
|
||||
return self;
|
||||
@ -218,6 +221,26 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
|
||||
return _delegate;
|
||||
}
|
||||
|
||||
- (void)setShouldRenderProgressImages:(BOOL)shouldRenderProgressImages
|
||||
{
|
||||
ASDN::MutexLocker l(_lock);
|
||||
if (shouldRenderProgressImages == _shouldRenderProgressImages) {
|
||||
return;
|
||||
}
|
||||
|
||||
_shouldRenderProgressImages = shouldRenderProgressImages;
|
||||
|
||||
|
||||
ASDN::MutexUnlocker u(_lock);
|
||||
[self _updateProgressImageBlockOnDownloaderIfNeeded];
|
||||
}
|
||||
|
||||
- (BOOL)shouldRenderProgressImages
|
||||
{
|
||||
ASDN::MutexLocker l(_lock);
|
||||
return _shouldRenderProgressImages;
|
||||
}
|
||||
|
||||
- (BOOL)placeholderShouldPersist
|
||||
{
|
||||
ASDN::MutexLocker l(_lock);
|
||||
@ -309,6 +332,8 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
|
||||
*/
|
||||
- (void)_updateProgressImageBlockOnDownloaderIfNeeded
|
||||
{
|
||||
BOOL shouldRenderProgressImages = self.shouldRenderProgressImages;
|
||||
|
||||
// Read our interface state before locking so that we don't lock super while holding our lock.
|
||||
ASInterfaceState interfaceState = self.interfaceState;
|
||||
ASDN::MutexLocker l(_lock);
|
||||
@ -318,7 +343,7 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
|
||||
}
|
||||
|
||||
ASImageDownloaderProgressImage progress = nil;
|
||||
if (ASInterfaceStateIncludesVisible(interfaceState)) {
|
||||
if (shouldRenderProgressImages && ASInterfaceStateIncludesVisible(interfaceState)) {
|
||||
__weak __typeof__(self) weakSelf = self;
|
||||
progress = ^(UIImage * _Nonnull progressImage, CGFloat progress, id _Nullable downloadIdentifier) {
|
||||
__typeof__(self) strongSelf = weakSelf;
|
||||
|
||||
@ -61,7 +61,16 @@ typedef void(^ASImageCacherCompletion)(id <ASImageContainerProtocol> _Nullable i
|
||||
|
||||
@end
|
||||
|
||||
/**
|
||||
@param image The image that was downloaded, if the image could be successfully downloaded; nil otherwise.
|
||||
@param error An error describing why the download of `URL` failed, if the download failed; nil otherwise.
|
||||
@param downloadIdentifier The identifier for the download task that completed.
|
||||
*/
|
||||
typedef void(^ASImageDownloaderCompletion)(id <ASImageContainerProtocol> _Nullable image, NSError * _Nullable error, id _Nullable downloadIdentifier);
|
||||
|
||||
/**
|
||||
@param progress The progress of the download, in the range of (0.0, 1.0), inclusive.
|
||||
*/
|
||||
typedef void(^ASImageDownloaderProgress)(CGFloat progress);
|
||||
typedef void(^ASImageDownloaderProgressImage)(UIImage *progressImage, CGFloat progress, id _Nullable downloadIdentifier);
|
||||
|
||||
@ -98,10 +107,7 @@ typedef NS_ENUM(NSUInteger, ASImageDownloaderPriority) {
|
||||
@param URL The URL of the image to download.
|
||||
@param callbackQueue The queue to call `downloadProgressBlock` and `completion` on.
|
||||
@param downloadProgress The block to be invoked when the download of `URL` progresses.
|
||||
@param progress The progress of the download, in the range of (0.0, 1.0), inclusive.
|
||||
@param completion The block to be invoked when the download has completed, or has failed.
|
||||
@param image The image that was downloaded, if the image could be successfully downloaded; nil otherwise.
|
||||
@param error An error describing why the download of `URL` failed, if the download failed; nil otherwise.
|
||||
@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.
|
||||
@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.
|
||||
@ -109,7 +115,7 @@ typedef NS_ENUM(NSUInteger, ASImageDownloaderPriority) {
|
||||
- (nullable id)downloadImageWithURL:(NSURL *)URL
|
||||
callbackQueue:(dispatch_queue_t)callbackQueue
|
||||
downloadProgress:(nullable ASImageDownloaderProgress)downloadProgress
|
||||
completion:(nullable ASImageDownloaderCompletion)completion;
|
||||
completion:(ASImageDownloaderCompletion)completion;
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@ -9,8 +9,12 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "ASImageProtocols.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface ASPINRemoteImageDownloader : NSObject <ASImageCacheProtocol, ASImageDownloaderProtocol>
|
||||
|
||||
+ (instancetype)sharedDownloader;
|
||||
+ (ASPINRemoteImageDownloader *)sharedDownloader;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@ -96,8 +96,9 @@
|
||||
|
||||
- (id <ASImageContainerProtocol>)synchronouslyFetchedCachedImageWithURL:(NSURL *)URL;
|
||||
{
|
||||
NSString *key = [[self sharedPINRemoteImageManager] cacheKeyForURL:URL processorKey:nil];
|
||||
PINRemoteImageManagerResult *result = [[self sharedPINRemoteImageManager] synchronousImageFromCacheWithCacheKey:key options:PINRemoteImageManagerDownloadOptionsSkipDecode];
|
||||
PINRemoteImageManager *manager = [self sharedPINRemoteImageManager];
|
||||
NSString *key = [manager cacheKeyForURL:URL processorKey:nil];
|
||||
PINRemoteImageManagerResult *result = [manager synchronousImageFromCacheWithCacheKey:key options:PINRemoteImageManagerDownloadOptionsSkipDecode];
|
||||
#if PIN_ANIMATED_AVAILABLE
|
||||
if (result.alternativeRepresentation) {
|
||||
return result.alternativeRepresentation;
|
||||
@ -133,7 +134,18 @@
|
||||
downloadProgress:(ASImageDownloaderProgress)downloadProgress
|
||||
completion:(ASImageDownloaderCompletion)completion;
|
||||
{
|
||||
return [[self sharedPINRemoteImageManager] downloadImageWithURL:URL options:PINRemoteImageManagerDownloadOptionsSkipDecode completion:^(PINRemoteImageManagerResult *result) {
|
||||
return [[self sharedPINRemoteImageManager] downloadImageWithURL:URL options:PINRemoteImageManagerDownloadOptionsSkipDecode progressDownload:^(int64_t completedBytes, int64_t totalBytes) {
|
||||
if (downloadProgress == nil) { return; }
|
||||
|
||||
/// If we're targeting the main queue and we're on the main thread, call immediately.
|
||||
if (ASDisplayNodeThreadIsMain() && callbackQueue == dispatch_get_main_queue()) {
|
||||
downloadProgress(totalBytes / (CGFloat)completedBytes);
|
||||
} else {
|
||||
dispatch_async(callbackQueue, ^{
|
||||
downloadProgress(totalBytes / (CGFloat)completedBytes);
|
||||
});
|
||||
}
|
||||
} completion:^(PINRemoteImageManagerResult * _Nonnull result) {
|
||||
/// If we're targeting the main queue and we're on the main thread, complete immediately.
|
||||
if (ASDisplayNodeThreadIsMain() && callbackQueue == dispatch_get_main_queue()) {
|
||||
#if PIN_ANIMATED_AVAILABLE
|
||||
|
||||
@ -37,6 +37,7 @@
|
||||
#if DISPLAYNODE_USE_LOCKS
|
||||
#define _bridge_prologue_read ASDN::MutexLocker l(_propertyLock); ASDisplayNodeAssertThreadAffinity(self)
|
||||
#define _bridge_prologue_write ASDN::MutexLocker l(_propertyLock)
|
||||
#define _bridge_prologue_write_unlock ASDN::MutexUnlocker u(_propertyLock)
|
||||
#else
|
||||
#define _bridge_prologue_read ASDisplayNodeAssertThreadAffinity(self)
|
||||
#define _bridge_prologue_write
|
||||
@ -331,7 +332,11 @@ if (shouldApply) { _layer.layerProperty = (layerValueExpr); } else { ASDisplayNo
|
||||
// The node is loaded and we're on main.
|
||||
// Quite the opposite of setNeedsDisplay, we must call __setNeedsLayout before messaging
|
||||
// the view or layer to ensure that measurement and implicitly added subnodes have been handled.
|
||||
|
||||
// Calling __setNeedsLayout while holding the property lock can cause deadlocks
|
||||
_bridge_prologue_write_unlock;
|
||||
[self __setNeedsLayout];
|
||||
_bridge_prologue_write;
|
||||
_messageToViewOrLayer(setNeedsLayout);
|
||||
} else if (__loaded(self)) {
|
||||
// The node is loaded but we're not on main.
|
||||
@ -341,7 +346,9 @@ if (shouldApply) { _layer.layerProperty = (layerValueExpr); } else { ASDisplayNo
|
||||
[ASDisplayNodeGetPendingState(self) setNeedsLayout];
|
||||
} else {
|
||||
// The node is not loaded and we're not on main.
|
||||
_bridge_prologue_write_unlock;
|
||||
[self __setNeedsLayout];
|
||||
_bridge_prologue_write;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -93,7 +93,9 @@ FOUNDATION_EXPORT NSString * const ASRenderingEngineDidDisplayNodesScheduledBefo
|
||||
ASDisplayNode * __weak _supernode;
|
||||
|
||||
ASSentinel *_displaySentinel;
|
||||
ASSentinel *_transitionSentinel;
|
||||
|
||||
int32_t _transitionID;
|
||||
BOOL _transitionInProgress;
|
||||
|
||||
// This is the desired contentsScale, not the scale at which the layer's contents should be displayed
|
||||
CGFloat _contentsScaleForDisplay;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||

|
||||
|
||||
[](http://cocoapods.org/pods/AsyncDisplayKit)
|
||||
[](http://cocoapods.org/pods/AsyncDisplayKit)
|
||||
[](http://cocoapods.org/pods/AsyncDisplayKit)
|
||||
[](http://cocoapods.org/pods/AsyncDisplayKit)
|
||||
|
||||
[](http://AsyncDisplayKit.org)
|
||||
[](http://AsyncDisplayKit.org)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user