[ASImageNode] Fix a threading issue which can cause a display completion block to never be executed (#1148)

- Clear _displayCompletionBlock while we still have the node's instance lock. Because it may not be the same block by the time the lock is reacquired. In other words, it can happen that another thread sets a new display block after this thread releases the lock but before it reacquires it. And we don't want to clear out the new block.
- Reduce a lock/unlock pair which should help perf a tiny bit.
This commit is contained in:
Huy Nguyen 2018-11-04 16:28:48 -08:00 committed by GitHub
parent c7d1465aba
commit e745aded7d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -533,8 +533,15 @@ static ASDN::StaticMutex& cacheLock = *new ASDN::StaticMutex;
[super displayDidFinish];
__instanceLock__.lock();
void (^displayCompletionBlock)(BOOL canceled) = _displayCompletionBlock;
UIImage *image = _image;
void (^displayCompletionBlock)(BOOL canceled) = _displayCompletionBlock;
BOOL shouldPerformDisplayCompletionBlock = (image && displayCompletionBlock);
// Clear the ivar now. The block is retained and will be executed shortly.
if (shouldPerformDisplayCompletionBlock) {
_displayCompletionBlock = nil;
}
BOOL hasDebugLabel = (_debugLabelNode != nil);
__instanceLock__.unlock();
@ -556,13 +563,8 @@ static ASDN::StaticMutex& cacheLock = *new ASDN::StaticMutex;
}
// If we've got a block to perform after displaying, do it.
if (image && displayCompletionBlock) {
if (shouldPerformDisplayCompletionBlock) {
displayCompletionBlock(NO);
__instanceLock__.lock();
_displayCompletionBlock = nil;
__instanceLock__.unlock();
}
}