Refactory the display link with a cross-platform implementation, CADisplayLink. for iOS/tvOS, CVDDisplayLink for macOS, NSTimer for watchOS
This commit is contained in:
parent
75fb66c834
commit
7e85869e6c
|
@ -196,6 +196,9 @@
|
|||
32D3CDCF21DDE87300C4DB49 /* UIImage+MemoryCacheCost.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D3CDCC21DDE87300C4DB49 /* UIImage+MemoryCacheCost.m */; };
|
||||
32D3CDD121DDE87300C4DB49 /* UIImage+MemoryCacheCost.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D3CDCD21DDE87300C4DB49 /* UIImage+MemoryCacheCost.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
32E5690822B1FFCA00CBABC6 /* SDWebImageOptionsProcessor.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 324406292296C5F400A36084 /* SDWebImageOptionsProcessor.h */; };
|
||||
32E67311235765B500DB4987 /* SDDisplayLink.h in Headers */ = {isa = PBXBuildFile; fileRef = 32E6730F235765B500DB4987 /* SDDisplayLink.h */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||
32E67312235765B500DB4987 /* SDDisplayLink.m in Sources */ = {isa = PBXBuildFile; fileRef = 32E67310235765B500DB4987 /* SDDisplayLink.m */; };
|
||||
32E67313235765B500DB4987 /* SDDisplayLink.m in Sources */ = {isa = PBXBuildFile; fileRef = 32E67310235765B500DB4987 /* SDDisplayLink.m */; };
|
||||
32EB6D8E206D132E005CAEF6 /* SDAnimatedImageRep.m in Sources */ = {isa = PBXBuildFile; fileRef = 320224BA203979BA00E9F285 /* SDAnimatedImageRep.m */; };
|
||||
32EB6D91206D132E005CAEF6 /* SDAnimatedImageRep.m in Sources */ = {isa = PBXBuildFile; fileRef = 320224BA203979BA00E9F285 /* SDAnimatedImageRep.m */; };
|
||||
32F21B5320788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F21B4F20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
|
@ -433,6 +436,8 @@
|
|||
32D1221D2080B2EB003685A3 /* SDImageCachesManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SDImageCachesManager.h; path = Core/SDImageCachesManager.h; sourceTree = "<group>"; };
|
||||
32D3CDCC21DDE87300C4DB49 /* UIImage+MemoryCacheCost.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIImage+MemoryCacheCost.m"; path = "Core/UIImage+MemoryCacheCost.m"; sourceTree = "<group>"; };
|
||||
32D3CDCD21DDE87300C4DB49 /* UIImage+MemoryCacheCost.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIImage+MemoryCacheCost.h"; path = "Core/UIImage+MemoryCacheCost.h"; sourceTree = "<group>"; };
|
||||
32E6730F235765B500DB4987 /* SDDisplayLink.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDDisplayLink.h; sourceTree = "<group>"; };
|
||||
32E67310235765B500DB4987 /* SDDisplayLink.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDDisplayLink.m; sourceTree = "<group>"; };
|
||||
32F21B4F20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SDWebImageDownloaderRequestModifier.h; path = Core/SDWebImageDownloaderRequestModifier.h; sourceTree = "<group>"; };
|
||||
32F21B5020788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SDWebImageDownloaderRequestModifier.m; path = Core/SDWebImageDownloaderRequestModifier.m; sourceTree = "<group>"; };
|
||||
32F7C06D2030114C00873181 /* SDImageTransformer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SDImageTransformer.h; path = Core/SDImageTransformer.h; sourceTree = "<group>"; };
|
||||
|
@ -547,7 +552,7 @@
|
|||
name = Decoder;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
32484756201775CE00AF9E5A /* ImageView */ = {
|
||||
32484756201775CE00AF9E5A /* AnimatedImage */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3248475B201775F600AF9E5A /* SDAnimatedImage.h */,
|
||||
|
@ -559,7 +564,7 @@
|
|||
320224B9203979BA00E9F285 /* SDAnimatedImageRep.h */,
|
||||
320224BA203979BA00E9F285 /* SDAnimatedImageRep.m */,
|
||||
);
|
||||
name = ImageView;
|
||||
name = AnimatedImage;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
328BB6972081FDAB00760D6C /* Manager */ = {
|
||||
|
@ -602,6 +607,8 @@
|
|||
32B5CC5F222F89C2005EB74E /* SDAsyncBlockOperation.m */,
|
||||
325C460622339426004CAE11 /* SDWeakProxy.h */,
|
||||
325C460722339426004CAE11 /* SDWeakProxy.m */,
|
||||
32E6730F235765B500DB4987 /* SDDisplayLink.h */,
|
||||
32E67310235765B500DB4987 /* SDDisplayLink.m */,
|
||||
325C460022339330004CAE11 /* SDImageAssetManager.h */,
|
||||
325C460122339330004CAE11 /* SDImageAssetManager.m */,
|
||||
325C460C223394D8004CAE11 /* SDImageCachesManagerOperation.h */,
|
||||
|
@ -706,7 +713,7 @@
|
|||
321E60831F38E88F00405457 /* Decoder */,
|
||||
328BB6982081FDD800760D6C /* Prefetcher */,
|
||||
328BB6992081FDDF00760D6C /* Transformer */,
|
||||
32484756201775CE00AF9E5A /* ImageView */,
|
||||
32484756201775CE00AF9E5A /* AnimatedImage */,
|
||||
53922DAC148C56DD0056699D /* Utils */,
|
||||
53922DA9148C562D0056699D /* Categories */,
|
||||
4369C2851D9811BB007E863A /* WebCache Categories */,
|
||||
|
@ -880,6 +887,7 @@
|
|||
80B6DF7F2142B43300BCB334 /* NSImage+Compatibility.h in Headers */,
|
||||
32C0FDE32013426C001B8F2D /* SDWebImageIndicator.h in Headers */,
|
||||
32F7C0712030114C00873181 /* SDImageTransformer.h in Headers */,
|
||||
32E67311235765B500DB4987 /* SDDisplayLink.h in Headers */,
|
||||
4A2CAE2D1AB4BB7500B6BC39 /* UIImage+GIF.h in Headers */,
|
||||
4A2CAE291AB4BB7500B6BC39 /* NSData+ImageContentType.h in Headers */,
|
||||
328BB69E2081FED200760D6C /* SDWebImageCacheKeyFilter.h in Headers */,
|
||||
|
@ -1076,6 +1084,7 @@
|
|||
3244062E2296C5F400A36084 /* SDWebImageOptionsProcessor.m in Sources */,
|
||||
3250C9F02355D9DA0093A896 /* SDWebImageDownloaderDecryptor.m in Sources */,
|
||||
328BB6A42081FED200760D6C /* SDWebImageCacheKeyFilter.m in Sources */,
|
||||
32E67313235765B500DB4987 /* SDDisplayLink.m in Sources */,
|
||||
4A2CAE2E1AB4BB7500B6BC39 /* UIImage+GIF.m in Sources */,
|
||||
80B6DF822142B44400BCB334 /* NSButton+WebCache.m in Sources */,
|
||||
32D3CDCF21DDE87300C4DB49 /* UIImage+MemoryCacheCost.m in Sources */,
|
||||
|
@ -1143,6 +1152,7 @@
|
|||
3244062D2296C5F400A36084 /* SDWebImageOptionsProcessor.m in Sources */,
|
||||
3250C9EF2355D9DA0093A896 /* SDWebImageDownloaderDecryptor.m in Sources */,
|
||||
328BB6A22081FED200760D6C /* SDWebImageCacheKeyFilter.m in Sources */,
|
||||
32E67312235765B500DB4987 /* SDDisplayLink.m in Sources */,
|
||||
53761309155AD0D5005750A4 /* SDImageCache.m in Sources */,
|
||||
80B6DF832142B44500BCB334 /* NSButton+WebCache.m in Sources */,
|
||||
32D3CDCE21DDE87300C4DB49 /* UIImage+MemoryCacheCost.m in Sources */,
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* This file is part of the SDWebImage package.
|
||||
* (c) Olivier Poitrey <rs@dailymotion.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "SDWebImageCompat.h"
|
||||
|
||||
@interface SDDisplayLink : NSObject
|
||||
|
||||
@property (readonly, nonatomic, weak, nullable) id target;
|
||||
@property (readonly, nonatomic, assign, nonnull) SEL selector;
|
||||
@property (readonly, nonatomic) CFTimeInterval duration;
|
||||
@property (readonly, nonatomic) BOOL isRunning;
|
||||
|
||||
+ (nonnull instancetype)displayLinkWithTarget:(nonnull id)target selector:(nonnull SEL)sel;
|
||||
|
||||
- (void)addToRunLoop:(nonnull NSRunLoop *)runloop forMode:(nonnull NSRunLoopMode)mode;
|
||||
- (void)removeFromRunLoop:(nonnull NSRunLoop *)runloop forMode:(nonnull NSRunLoopMode)mode;
|
||||
|
||||
- (void)start;
|
||||
- (void)stop;
|
||||
|
||||
@end
|
|
@ -0,0 +1,190 @@
|
|||
/*
|
||||
* This file is part of the SDWebImage package.
|
||||
* (c) Olivier Poitrey <rs@dailymotion.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
#import "SDDisplayLink.h"
|
||||
#import "SDWeakProxy.h"
|
||||
#if SD_MAC
|
||||
#import <CoreVideo/CoreVideo.h>
|
||||
#elif SD_IOS || SD_TV
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
#endif
|
||||
|
||||
#if SD_MAC
|
||||
static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp *inNow, const CVTimeStamp *inOutputTime, CVOptionFlags flagsIn, CVOptionFlags *flagsOut, void *displayLinkContext);
|
||||
#endif
|
||||
|
||||
#if SD_WATCH
|
||||
#define kSDDisplayLinkInterval 1.0 / 60
|
||||
#endif
|
||||
|
||||
@interface SDDisplayLink ()
|
||||
|
||||
#if SD_MAC
|
||||
@property (nonatomic, assign) CVDisplayLinkRef displayLink;
|
||||
#elif SD_IOS || SD_TV
|
||||
@property (nonatomic, strong) CADisplayLink *displayLink;
|
||||
#else
|
||||
@property (nonatomic, strong) NSTimer *displayLink;
|
||||
#endif
|
||||
|
||||
@end
|
||||
|
||||
@implementation SDDisplayLink
|
||||
|
||||
- (void)dealloc {
|
||||
#if SD_MAC
|
||||
if (_displayLink) {
|
||||
CVDisplayLinkRelease(_displayLink);
|
||||
_displayLink = NULL;
|
||||
}
|
||||
#elif SD_IOS || SD_TV
|
||||
[_displayLink invalidate];
|
||||
_displayLink = nil;
|
||||
#else
|
||||
[_displayLink invalidate];
|
||||
_displayLink = nil;
|
||||
#endif
|
||||
}
|
||||
|
||||
- (instancetype)initWithTarget:(id)target selector:(SEL)sel {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_target = target;
|
||||
_selector = sel;
|
||||
#if SD_MAC
|
||||
CVDisplayLinkCreateWithActiveCGDisplays(&_displayLink);
|
||||
CVDisplayLinkSetOutputCallback(_displayLink, DisplayLinkCallback, (__bridge void *)self);
|
||||
#elif SD_IOS || SD_TV
|
||||
SDWeakProxy *weakProxy = [SDWeakProxy proxyWithTarget:self];
|
||||
_displayLink = [CADisplayLink displayLinkWithTarget:weakProxy selector:@selector(displayLinkDidRefresh:)];
|
||||
#else
|
||||
SDWeakProxy *weakProxy = [SDWeakProxy proxyWithTarget:self];
|
||||
_displayLink = [NSTimer timerWithTimeInterval:kSDDisplayLinkInterval target:weakProxy selector:@selector(displayLinkDidRefresh:) userInfo:nil repeats:YES];
|
||||
#endif
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (instancetype)displayLinkWithTarget:(id)target selector:(SEL)sel {
|
||||
SDDisplayLink *displayLink = [[SDDisplayLink alloc] initWithTarget:target selector:sel];
|
||||
return displayLink;
|
||||
}
|
||||
|
||||
- (CFTimeInterval)duration {
|
||||
#if SD_MAC
|
||||
CVTimeStamp nowTime;
|
||||
CVDisplayLinkGetCurrentTime(_displayLink, &nowTime);
|
||||
NSTimeInterval duration = (double)nowTime.videoRefreshPeriod / ((double)nowTime.videoTimeScale * nowTime.rateScalar);
|
||||
#elif SD_IOS || SD_TV
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
NSTimeInterval duration = self.displayLink.duration * self.displayLink.frameInterval;
|
||||
#pragma clang diagnostic pop
|
||||
#else
|
||||
NSTimeInterval duration = 1.0 / 60;
|
||||
#endif
|
||||
return duration;
|
||||
}
|
||||
|
||||
- (BOOL)isRunning {
|
||||
#if SD_MAC
|
||||
return CVDisplayLinkIsRunning(self.displayLink);
|
||||
#elif SD_IOS || SD_TV
|
||||
return !self.displayLink.isPaused;
|
||||
#else
|
||||
return self.displayLink.isValid;
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)addToRunLoop:(NSRunLoop *)runloop forMode:(NSRunLoopMode)mode {
|
||||
if (!runloop || !mode) {
|
||||
return;
|
||||
}
|
||||
#if SD_MAC
|
||||
// CVDisplayLink does not use runloop
|
||||
#elif SD_IOS || SD_TV
|
||||
[self.displayLink addToRunLoop:runloop forMode:mode];
|
||||
#else
|
||||
CFRunLoopMode cfMode;
|
||||
if ([mode isEqualToString:NSDefaultRunLoopMode]) {
|
||||
cfMode = kCFRunLoopDefaultMode;
|
||||
} else if ([mode isEqualToString:NSRunLoopCommonModes]) {
|
||||
cfMode = kCFRunLoopCommonModes;
|
||||
} else {
|
||||
cfMode = (__bridge CFStringRef)mode;
|
||||
}
|
||||
CFRunLoopAddTimer(runloop.getCFRunLoop, (__bridge CFRunLoopTimerRef)self.displayLink, cfMode);
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)removeFromRunLoop:(NSRunLoop *)runloop forMode:(NSRunLoopMode)mode {
|
||||
if (!runloop || !mode) {
|
||||
return;
|
||||
}
|
||||
#if SD_MAC
|
||||
// CVDisplayLink does not use runloop
|
||||
#elif SD_IOS || SD_TV
|
||||
[self.displayLink removeFromRunLoop:runloop forMode:mode];
|
||||
#else
|
||||
CFRunLoopMode cfMode;
|
||||
if ([mode isEqualToString:NSDefaultRunLoopMode]) {
|
||||
cfMode = kCFRunLoopDefaultMode;
|
||||
} else if ([mode isEqualToString:NSRunLoopCommonModes]) {
|
||||
cfMode = kCFRunLoopCommonModes;
|
||||
} else {
|
||||
cfMode = (__bridge CFStringRef)mode;
|
||||
}
|
||||
CFRunLoopRemoveTimer(runloop.getCFRunLoop, (__bridge CFRunLoopTimerRef)self.displayLink, cfMode);
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)start {
|
||||
#if SD_MAC
|
||||
CVDisplayLinkStart(self.displayLink);
|
||||
#elif SD_IOS || SD_TV
|
||||
self.displayLink.paused = NO;
|
||||
#else
|
||||
if (self.displayLink.isValid) {
|
||||
[self.displayLink fire];
|
||||
} else {
|
||||
SDWeakProxy *weakProxy = [SDWeakProxy proxyWithTarget:self];
|
||||
self.displayLink = [NSTimer timerWithTimeInterval:kSDDisplayLinkInterval target:weakProxy selector:@selector(displayLinkDidRefresh:) userInfo:nil repeats:YES];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)stop {
|
||||
#if SD_MAC
|
||||
CVDisplayLinkStop(self.displayLink);
|
||||
#elif SD_IOS || SD_TV
|
||||
self.displayLink.paused = YES;
|
||||
#else
|
||||
[self.displayLink invalidate];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)displayLinkDidRefresh:(id)displayLink {
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
|
||||
[_target performSelector:_selector withObject:self];
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#if SD_MAC
|
||||
static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp *inNow, const CVTimeStamp *inOutputTime, CVOptionFlags flagsIn, CVOptionFlags *flagsOut, void *displayLinkContext) {
|
||||
// CVDisplayLink callback is not on main queue
|
||||
SDDisplayLink *object = (__bridge SDDisplayLink *)displayLinkContext;
|
||||
__weak SDDisplayLink *weakObject = object;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[weakObject displayLinkDidRefresh:(__bridge id)(displayLink)];
|
||||
});
|
||||
return kCVReturnSuccess;
|
||||
}
|
||||
#endif
|
Loading…
Reference in New Issue