Merge pull request #3531 from dreampiggy/bugfix/macos_SDDisplayLink_crash_during_dealloc

Try to fix macOS SDDisplayLink crash because of accessing the deallocated objc pointer during CVDisplayLinkRef callback
This commit is contained in:
DreamPiggy 2023-05-10 16:31:15 +08:00 committed by GitHub
commit d82f5574e4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 7 additions and 3 deletions

View File

@ -45,6 +45,7 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt
- (void)dealloc {
#if SD_MAC
if (_displayLink) {
CVDisplayLinkStop(_displayLink);
CVDisplayLinkRelease(_displayLink);
_displayLink = NULL;
}
@ -62,14 +63,15 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt
if (self) {
_target = target;
_selector = sel;
// CA/CV/NSTimer will retain to the target, we need to break this using weak proxy
SDWeakProxy *weakProxy = [SDWeakProxy proxyWithTarget:self];
#if SD_MAC
CVDisplayLinkCreateWithActiveCGDisplays(&_displayLink);
CVDisplayLinkSetOutputCallback(_displayLink, DisplayLinkCallback, (__bridge void *)self);
// Simulate retain for target, the target is weak proxy to self
CVDisplayLinkSetOutputCallback(_displayLink, DisplayLinkCallback, (__bridge_retained void *)weakProxy);
#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
}
@ -238,7 +240,9 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt
#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
// Actually `SDWeakProxy` but not `SDDisplayLink`
SDDisplayLink *object = (__bridge SDDisplayLink *)displayLinkContext;
if (!object) return kCVReturnSuccess;
// 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 = object.runloopMode;