Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support the runloop mode control for macOS. Which can be useful when user want to pause animation when drag the mouse, or presenting modal window #2886

Merged
merged 2 commits into from Nov 6, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 2 additions & 3 deletions SDWebImage/Core/SDAnimatedImageView.h
Expand Up @@ -81,13 +81,12 @@
*/
@property (nonatomic, assign) BOOL resetFrameIndexWhenStopped;

#if SD_UIKIT
/**
You can specify a runloop mode to let it rendering.
Default is NSRunLoopCommonModes on multi-core iOS device, NSDefaultRunLoopMode on single-core iOS device
Default is NSRunLoopCommonModes on multi-core device, NSDefaultRunLoopMode on single-core device
@note This is useful for some cases, for example, always specify NSDefaultRunLoopMode, if you want to pause the animation when user scroll (for Mac user, drag the mouse or touchpad)
*/
@property (nonatomic, copy, nonnull) NSRunLoopMode runLoopMode;
#endif
@end

#endif
15 changes: 14 additions & 1 deletion SDWebImage/Core/SDAnimatedImageView.m
Expand Up @@ -18,6 +18,7 @@

@interface SDAnimatedImageView () <CALayerDelegate> {
BOOL _initFinished; // Extra flag to mark the `commonInit` is called
NSRunLoopMode _runLoopMode;
double _playbackRate;
}

Expand Down Expand Up @@ -149,6 +150,9 @@ - (void)setImage:(UIImage *)image
self.player.totalLoopCount = self.animationRepeatCount;
}

// RunLoop Mode
self.player.runLoopMode = self.runLoopMode;

// Play Rate
self.player.playbackRate = self.playbackRate;

Expand Down Expand Up @@ -188,12 +192,21 @@ - (void)setImage:(UIImage *)image

- (void)setRunLoopMode:(NSRunLoopMode)runLoopMode
{
_runLoopMode = [runLoopMode copy];
self.player.runLoopMode = runLoopMode;
}

- (NSRunLoopMode)runLoopMode
{
return self.player.runLoopMode;
if (!_runLoopMode) {
_runLoopMode = [[self class] defaultRunLoopMode];
}
return _runLoopMode;
}

+ (NSString *)defaultRunLoopMode {
// Key off `activeProcessorCount` (as opposed to `processorCount`) since the system could shut down cores in certain situations.
return [NSProcessInfo processInfo].activeProcessorCount > 1 ? NSRunLoopCommonModes : NSDefaultRunLoopMode;
}

- (void)setPlaybackRate:(double)playbackRate
Expand Down
15 changes: 12 additions & 3 deletions SDWebImage/Private/SDDisplayLink.m
Expand Up @@ -25,12 +25,13 @@ @interface SDDisplayLink ()
#if SD_MAC
@property (nonatomic, assign) CVDisplayLinkRef displayLink;
@property (nonatomic, assign) CVTimeStamp outputTime;
@property (nonatomic, copy) NSRunLoopMode runloopMode;
#elif SD_IOS || SD_TV
@property (nonatomic, strong) CADisplayLink *displayLink;
#else
@property (nonatomic, strong) NSTimer *displayLink;
@property (nonatomic, strong) NSRunLoop *runloop;
@property (nonatomic, strong) NSRunLoopMode runloopMode;
@property (nonatomic, copy) NSRunLoopMode runloopMode;
@property (nonatomic, assign) NSTimeInterval currentFireDate;
#endif

Expand Down Expand Up @@ -118,7 +119,7 @@ - (void)addToRunLoop:(NSRunLoop *)runloop forMode:(NSRunLoopMode)mode {
return;
}
#if SD_MAC
// CVDisplayLink does not use runloop
self.runloopMode = mode;
#elif SD_IOS || SD_TV
[self.displayLink addToRunLoop:runloop forMode:mode];
#else
Expand All @@ -141,7 +142,7 @@ - (void)removeFromRunLoop:(NSRunLoop *)runloop forMode:(NSRunLoopMode)mode {
return;
}
#if SD_MAC
// CVDisplayLink does not use runloop
self.runloopMode = nil;
#elif SD_IOS || SD_TV
[self.displayLink removeFromRunLoop:runloop forMode:mode];
#else
Expand Down Expand Up @@ -186,6 +187,14 @@ - (void)stop {
}

- (void)displayLinkDidRefresh:(id)displayLink {
#if SD_MAC
// CVDisplayLink does not use runloop, but we can provide similar behavior for modes
// May use `default` runloop to avoid extra callback when in `eventTracking` (mouse drag, scroll) or `modalPanel` (modal panel)
NSString *runloopMode = self.runloopMode;
if (![runloopMode isEqualToString:NSRunLoopCommonModes] && ![runloopMode isEqualToString:NSRunLoop.mainRunLoop.currentMode]) {
return;
}
#endif
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[_target performSelector:_selector withObject:self];
Expand Down