Using the lazy property for `lock` and `runLoopMode` to ensure this will not cause crash and logic issue. Without need of checking on `setImage:`

This commit is contained in:
DreamPiggy 2019-05-16 00:34:52 +08:00
parent 63c0794ad8
commit 1d5b411f3c
2 changed files with 43 additions and 21 deletions

View File

@ -40,7 +40,10 @@ static NSUInteger SDDeviceFreeMemory() {
return vm_stat.free_count * page_size;
}
@interface SDAnimatedImageView () <CALayerDelegate>
@interface SDAnimatedImageView () <CALayerDelegate> {
NSRunLoopMode _runLoopMode;
BOOL _initFinished; // Extra flag to mark the `commonInit` is called
}
@property (nonatomic, strong, readwrite) UIImage *currentFrame;
@property (nonatomic, assign, readwrite) NSUInteger currentFrameIndex;
@ -62,7 +65,6 @@ static NSUInteger SDDeviceFreeMemory() {
#else
@property (nonatomic, strong) CADisplayLink *displayLink;
#endif
@property (nonatomic, assign) BOOL hasInitialized;
@end
@ -124,14 +126,10 @@ static NSUInteger SDDeviceFreeMemory() {
- (void)commonInit
{
if (self.hasInitialized) {
return;
}
self.hasInitialized = YES;
// Pay attention that UIKit's `initWithImage:` will trigger a `setImage:` during initialization before this `commonInit`.
// So the properties which rely on this order, should using lazy-evaluation or do extra check in `setImage:`.
self.shouldCustomLoopCount = NO;
self.shouldIncrementalLoad = YES;
self.lock = dispatch_semaphore_create(1);
#if SD_MAC
self.wantsLayer = YES;
// Default value from `NSImageView`
@ -140,9 +138,10 @@ static NSUInteger SDDeviceFreeMemory() {
self.imageAlignment = NSImageAlignCenter;
#endif
#if SD_UIKIT
self.runLoopMode = [[self class] defaultRunLoopMode];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveMemoryWarning:) name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
#endif
// Mark commonInit finished
_initFinished = YES;
}
- (void)resetAnimatedImage
@ -189,11 +188,6 @@ static NSUInteger SDDeviceFreeMemory() {
return;
}
// Check has initlized
if (!self.hasInitialized) {
[self commonInit];
}
// Check Progressive rendering
[self updateIsProgressiveWithImage:image];
@ -251,17 +245,38 @@ static NSUInteger SDDeviceFreeMemory() {
}
#if SD_UIKIT
- (void)setRunLoopMode:(NSString *)runLoopMode
- (void)setRunLoopMode:(NSRunLoopMode)runLoopMode
{
if (![@[NSDefaultRunLoopMode, NSRunLoopCommonModes] containsObject:runLoopMode]) {
NSAssert(NO, @"Invalid run loop mode: %@", runLoopMode);
_runLoopMode = [[self class] defaultRunLoopMode];
} else {
_runLoopMode = runLoopMode;
if ([_runLoopMode isEqualToString:runLoopMode]) {
return;
}
if (_displayLink) {
if (_runLoopMode) {
[_displayLink removeFromRunLoop:[NSRunLoop mainRunLoop] forMode:_runLoopMode];
}
if (runLoopMode) {
[_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:runLoopMode];
}
}
_runLoopMode = [runLoopMode copy];
}
- (NSRunLoopMode)runLoopMode
{
if (!_runLoopMode) {
_runLoopMode = [[self class] defaultRunLoopMode];
}
return _runLoopMode;
}
#endif
- (BOOL)shouldIncrementalLoad {
if (!_initFinished) {
return YES; // Defaults to YES
}
return _initFinished;
}
#pragma mark - Private
- (NSOperationQueue *)fetchQueue
{
@ -280,6 +295,13 @@ static NSUInteger SDDeviceFreeMemory() {
return _frameBuffer;
}
- (dispatch_semaphore_t)lock {
if (!_lock) {
_lock = dispatch_semaphore_create(1);
}
return _lock;
}
#if SD_MAC
- (CVDisplayLinkRef)displayLink
{

View File

@ -156,7 +156,7 @@ static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop coun
#endif
}
- (void)test12AnimatedImageViewInitWithImage {
- (void)test13AnimatedImageViewInitWithImage {
// Test that -[SDAnimatedImageView initWithImage:] this convenience initializer not crash
SDAnimatedImage *image = [SDAnimatedImage imageWithData:[self testAPNGPData]];
SDAnimatedImageView *imageView;