mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-23 22:55:00 +00:00
Limit 1 inflight Photos.framework request per multiplex image node
This commit is contained in:
@@ -66,6 +66,7 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent
|
|||||||
id _loadedImageIdentifier;
|
id _loadedImageIdentifier;
|
||||||
id _loadingImageIdentifier;
|
id _loadingImageIdentifier;
|
||||||
id _displayedImageIdentifier;
|
id _displayedImageIdentifier;
|
||||||
|
NSOperation *_phImageRequestOperation;
|
||||||
|
|
||||||
// Networking.
|
// Networking.
|
||||||
id _downloadIdentifier;
|
id _downloadIdentifier;
|
||||||
@@ -168,12 +169,21 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent
|
|||||||
return [self initWithCache:nil downloader:nil]; // satisfy compiler
|
return [self initWithCache:nil downloader:nil]; // satisfy compiler
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)dealloc {
|
||||||
|
[_phImageRequestOperation cancel];
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark - ASDisplayNode Overrides
|
#pragma mark - ASDisplayNode Overrides
|
||||||
- (void)clearContents
|
- (void)clearContents
|
||||||
{
|
{
|
||||||
[super clearContents]; // This actually clears the contents, so we need to do this first for our displayedImageIdentifier to be meaningful.
|
[super clearContents]; // This actually clears the contents, so we need to do this first for our displayedImageIdentifier to be meaningful.
|
||||||
[self _setDisplayedImageIdentifier:nil withImage:nil];
|
[self _setDisplayedImageIdentifier:nil withImage:nil];
|
||||||
|
|
||||||
|
if (_phImageRequestOperation) {
|
||||||
|
[_phImageRequestOperation cancel];
|
||||||
|
_phImageRequestOperation = nil;
|
||||||
|
}
|
||||||
|
|
||||||
if (_downloadIdentifier) {
|
if (_downloadIdentifier) {
|
||||||
[_downloader cancelImageDownloadForIdentifier:_downloadIdentifier];
|
[_downloader cancelImageDownloadForIdentifier:_downloadIdentifier];
|
||||||
_downloadIdentifier = nil;
|
_downloadIdentifier = nil;
|
||||||
@@ -521,22 +531,33 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent
|
|||||||
/*
|
/*
|
||||||
* Locking rationale:
|
* Locking rationale:
|
||||||
* As of iOS 9, Photos.framework will eventually deadlock if you hit it with concurrent fetch requests. rdar://22984886
|
* As of iOS 9, Photos.framework will eventually deadlock if you hit it with concurrent fetch requests. rdar://22984886
|
||||||
* Image requests are OK, but metadata requests aren't, so we limit ourselves to one at a time.
|
* Concurrent image requests are OK, but metadata requests aren't, so we limit ourselves to one at a time.
|
||||||
|
|
||||||
* -[PHFetchResult dealloc] plays a role in this deadlock, so we help the fetch result die ASAP by never storing it.
|
|
||||||
*/
|
*/
|
||||||
static NSLock *phRequestLock;
|
static NSLock *phRequestLock;
|
||||||
|
static NSOperationQueue *phImageRequestQueue;
|
||||||
static dispatch_once_t onceToken;
|
static dispatch_once_t onceToken;
|
||||||
dispatch_once(&onceToken, ^{
|
dispatch_once(&onceToken, ^{
|
||||||
phRequestLock = [NSLock new];
|
phRequestLock = [NSLock new];
|
||||||
|
phImageRequestQueue = [NSOperationQueue new];
|
||||||
|
phImageRequestQueue.maxConcurrentOperationCount = 10;
|
||||||
|
phImageRequestQueue.name = @"org.AsyncDisplayKit.MultiplexImageNode.phImageRequestQueue";
|
||||||
});
|
});
|
||||||
|
|
||||||
// This is sometimes called on main but there's no reason to stay there
|
// Each ASMultiplexImageNode can have max 1 inflight Photos image request operation
|
||||||
dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{
|
[_phImageRequestOperation cancel];
|
||||||
|
|
||||||
|
__weak __typeof(self)weakSelf = self;
|
||||||
|
_phImageRequestOperation = [NSBlockOperation blockOperationWithBlock:^{
|
||||||
|
__strong __typeof(weakSelf)strongSelf = weakSelf;
|
||||||
|
if (strongSelf == nil) { return; }
|
||||||
|
|
||||||
// Get the PHAsset itself.
|
// Get the PHAsset itself.
|
||||||
[phRequestLock lock];
|
[phRequestLock lock];
|
||||||
PHAsset *imageAsset = [PHAsset fetchAssetsWithLocalIdentifiers:@[request.assetIdentifier] options:nil].firstObject;
|
PHAsset *imageAsset;
|
||||||
|
// -[PHFetchResult dealloc] plays a role in the deadlock mentioned above, so we make sure the PHFetchResult is deallocated inside the critical section
|
||||||
|
@autoreleasepool {
|
||||||
|
imageAsset = [PHAsset fetchAssetsWithLocalIdentifiers:@[request.assetIdentifier] options:nil].firstObject;
|
||||||
|
}
|
||||||
[phRequestLock unlock];
|
[phRequestLock unlock];
|
||||||
|
|
||||||
if (imageAsset == nil) {
|
if (imageAsset == nil) {
|
||||||
@@ -558,7 +579,7 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent
|
|||||||
options.synchronous = YES;
|
options.synchronous = YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
PHImageManager *imageManager = self.imageManager ?: PHImageManager.defaultManager;
|
PHImageManager *imageManager = strongSelf.imageManager ?: PHImageManager.defaultManager;
|
||||||
[imageManager requestImageForAsset:imageAsset targetSize:request.targetSize contentMode:request.contentMode options:options resultHandler:^(UIImage *image, NSDictionary *info) {
|
[imageManager requestImageForAsset:imageAsset targetSize:request.targetSize contentMode:request.contentMode options:options resultHandler:^(UIImage *image, NSDictionary *info) {
|
||||||
if (NSThread.isMainThread) {
|
if (NSThread.isMainThread) {
|
||||||
dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{
|
dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{
|
||||||
@@ -568,7 +589,8 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent
|
|||||||
completionBlock(image, info[PHImageErrorKey]);
|
completionBlock(image, info[PHImageErrorKey]);
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
});
|
}];
|
||||||
|
[phImageRequestQueue addOperation:_phImageRequestOperation];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_fetchImageWithIdentifierFromCache:(id)imageIdentifier URL:(NSURL *)imageURL completion:(void (^)(UIImage *image))completionBlock
|
- (void)_fetchImageWithIdentifierFromCache:(id)imageIdentifier URL:(NSURL *)imageURL completion:(void (^)(UIImage *image))completionBlock
|
||||||
|
|||||||
Reference in New Issue
Block a user