From d5de41e9f9f5841523a3b72c94f5a3a180d453c2 Mon Sep 17 00:00:00 2001 From: Hayden Ball Date: Sat, 16 Apr 2022 18:00:22 +0100 Subject: [PATCH 01/11] refactor(_DTXTimerTrampoline): Simplify [_DTXTimerTrampoline fire:] --- DetoxSync/DetoxSync/Spies/NSTimer+DTXSpy.m | 2 +- .../SyncResources/DTXTimerSyncResource.h | 2 +- .../DetoxSync/Utils/_DTXTimerTrampoline.m | 49 +++++-------------- 3 files changed, 15 insertions(+), 38 deletions(-) diff --git a/DetoxSync/DetoxSync/Spies/NSTimer+DTXSpy.m b/DetoxSync/DetoxSync/Spies/NSTimer+DTXSpy.m index 8f5549c..b4bf5ce 100644 --- a/DetoxSync/DetoxSync/Spies/NSTimer+DTXSpy.m +++ b/DetoxSync/DetoxSync/Spies/NSTimer+DTXSpy.m @@ -52,7 +52,7 @@ static void _DTXCFTimerTrampoline(CFRunLoopTimerRef timer, void *info) // NSLog(@"❤️ %p", timer); id tp = [DTXTimerSyncResource existingTimerProxyWithTimer:NS(timer)]; - [tp fire:(__bridge NSTimer*)timer]; + [tp fire]; } static CFRunLoopTimerRef (*__orig_CFRunLoopTimerCreate)(CFAllocatorRef allocator, CFAbsoluteTime fireDate, CFTimeInterval interval, CFOptionFlags flags, CFIndex order, CFRunLoopTimerCallBack callout, CFRunLoopTimerContext *context); diff --git a/DetoxSync/DetoxSync/SyncResources/DTXTimerSyncResource.h b/DetoxSync/DetoxSync/SyncResources/DTXTimerSyncResource.h index a122819..cc794d1 100644 --- a/DetoxSync/DetoxSync/SyncResources/DTXTimerSyncResource.h +++ b/DetoxSync/DetoxSync/SyncResources/DTXTimerSyncResource.h @@ -22,7 +22,7 @@ NS_ASSUME_NONNULL_BEGIN //NSTimer @property (nonatomic, weak) NSTimer* timer; -- (void)fire:(NSTimer*)timer; +- (void)fire; @property (nonatomic) CFRunLoopRef runLoop; //CADisplayLink diff --git a/DetoxSync/DetoxSync/Utils/_DTXTimerTrampoline.m b/DetoxSync/DetoxSync/Utils/_DTXTimerTrampoline.m index 5235fdc..f0eaadb 100644 --- a/DetoxSync/DetoxSync/Utils/_DTXTimerTrampoline.m +++ b/DetoxSync/DetoxSync/Utils/_DTXTimerTrampoline.m @@ -112,47 +112,24 @@ - (void)setDisplayLink:(CADisplayLink*)displayLink #endif } -- (void)fire:(id)timer +- (void)fire { - //This is to ensure the timer is still valid after fire. - CFRunLoopRef runloop = CFRunLoopGetCurrent(); - CFRunLoopMode mode = CFRunLoopCopyCurrentMode(runloop); - CFRunLoopPerformBlock(runloop, mode, ^{ - if(CFRunLoopTimerIsValid((__bridge CFRunLoopTimerRef)timer) == NO) - { - [self untrack]; - - CFRelease(mode); - - return; - } - - CFRunLoopPerformBlock(runloop, mode, ^{ - if(CFRunLoopTimerIsValid((__bridge CFRunLoopTimerRef)timer) == NO) - { - [self untrack]; - - CFRelease(mode); - - return; - } - - CFRelease(mode); - }); - }); - if(_callback) { CFRunLoopTimerContext ctx; - CFRunLoopTimerGetContext((__bridge CFRunLoopTimerRef)timer, &ctx); - _callback((__bridge CFRunLoopTimerRef)timer, ctx.info); - return; + CFRunLoopTimerGetContext((__bridge CFRunLoopTimerRef)_timer, &ctx); + _callback((__bridge CFRunLoopTimerRef)_timer, ctx.info); + } + + if(_target && _sel) { + IMP impl = [_target methodForSelector:_sel]; + void (*func)(id, SEL, NSTimer*) = (void *)impl; + func(_target, _sel, _timer); + } + + if(!_repeats) { + [self untrack]; } - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Warc-performSelector-leaks" - [_target performSelector:_sel withObject:timer]; -#pragma clang diagnostic pop } - (void)track From 129ed8c85478901f21aea848e31b949c3cfa6265 Mon Sep 17 00:00:00 2001 From: Hayden Ball Date: Sat, 16 Apr 2022 18:05:06 +0100 Subject: [PATCH 02/11] style(_DTXTimerTrampoline): Correct indentation --- .../DetoxSync/Utils/_DTXTimerTrampoline.m | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/DetoxSync/DetoxSync/Utils/_DTXTimerTrampoline.m b/DetoxSync/DetoxSync/Utils/_DTXTimerTrampoline.m index f0eaadb..297b439 100644 --- a/DetoxSync/DetoxSync/Utils/_DTXTimerTrampoline.m +++ b/DetoxSync/DetoxSync/Utils/_DTXTimerTrampoline.m @@ -16,19 +16,19 @@ @implementation _DTXTimerTrampoline { id _target; SEL _sel; - + //NSTimer __weak NSTimer* _timer; CFRunLoopTimerCallBack _callback; CFRunLoopRef _runLoop; NSString* _timerDescription; NSTimeInterval _timeUntilFire; - + //CADisplayLink __weak CADisplayLink* _displayLink; - + BOOL _tracking; - + #if DEBUG NSString* _history; #endif @@ -53,7 +53,7 @@ - (instancetype)initWithTarget:(id)target selector:(SEL)selector fireDate:(NSDat _timeUntilFire = [fireDate timeIntervalSinceNow]; _ti = ti; _repeats = rep; - + #if DEBUG _history = [NSString stringWithFormat:@"%@\n%@", NSStringFromSelector(_cmd), NSThread.callStackSymbols]; #endif @@ -71,7 +71,7 @@ - (instancetype)initWithCallback:(CFRunLoopTimerCallBack)callback fireDate:(NSDa _timeUntilFire = [fireDate timeIntervalSinceNow]; _ti = ti; _repeats = rep; - + #if DEBUG _history = [NSString stringWithFormat:@"%@\n%@", NSStringFromSelector(_cmd), NSThread.callStackSymbols]; #endif @@ -87,7 +87,7 @@ - (BOOL)isDead - (void)dealloc { [self untrack]; - + objc_setAssociatedObject(_timer, __DTXTimerTrampolineKey, nil, OBJC_ASSOCIATION_RETAIN); } @@ -96,7 +96,7 @@ - (void)setTimer:(NSTimer*)timer _timer = timer; _timerDescription = [[timer debugDescription] copy]; objc_setAssociatedObject(timer, __DTXTimerTrampolineKey, self, OBJC_ASSOCIATION_RETAIN); - + #if DEBUG _history = [NSString stringWithFormat:@"%@\n%@", _history, [timer debugDescription]]; #endif @@ -138,7 +138,7 @@ - (void)track { return; } - + _tracking = YES; [DTXTimerSyncResource.sharedInstance trackTimerTrampoline:self]; } @@ -149,9 +149,9 @@ - (void)untrack { return; } - + // NSLog(@"🤦‍♂️ untrack: %@", _timer); - + [DTXTimerSyncResource.sharedInstance untrackTimerTrampoline:self]; _tracking = NO; } @@ -169,12 +169,12 @@ + (NSDateFormatter*)_descriptionDateFormatter } - (DTXBusyResource *)jsonDescription { - return @{ - @"fire_date": _fireDate ? [_DTXTimerTrampoline._descriptionDateFormatter stringFromDate:_fireDate] : @"none", - @"time_until_fire": @(_timeUntilFire), - @"is_recurring": @(_repeats), - @"repeat_interval": @(_ti) - }; + return @{ + @"fire_date": _fireDate ? [_DTXTimerTrampoline._descriptionDateFormatter stringFromDate:_fireDate] : @"none", + @"time_until_fire": @(_timeUntilFire), + @"is_recurring": @(_repeats), + @"repeat_interval": @(_ti) + }; } #if DEBUG From d3c2af41f800ce70a47091a8e1b397d88b7a2da9 Mon Sep 17 00:00:00 2001 From: Hayden Ball Date: Sat, 16 Apr 2022 18:12:48 +0100 Subject: [PATCH 03/11] doc(NSTimer+DTXSpy): What is going on? --- DetoxSync/DetoxSync/Spies/NSTimer+DTXSpy.m | 3 +++ 1 file changed, 3 insertions(+) diff --git a/DetoxSync/DetoxSync/Spies/NSTimer+DTXSpy.m b/DetoxSync/DetoxSync/Spies/NSTimer+DTXSpy.m index b4bf5ce..4074462 100644 --- a/DetoxSync/DetoxSync/Spies/NSTimer+DTXSpy.m +++ b/DetoxSync/DetoxSync/Spies/NSTimer+DTXSpy.m @@ -72,6 +72,9 @@ CFRunLoopTimerRef __detox_sync_CFRunLoopTimerCreate(CFAllocatorRef allocator, CF static CFRunLoopTimerRef (*__orig_CFRunLoopTimerCreateWithHandler)(CFAllocatorRef allocator, CFAbsoluteTime fireDate, CFTimeInterval interval, CFOptionFlags flags, CFIndex order, void (^block) (CFRunLoopTimerRef timer)); CFRunLoopTimerRef __detox_sync_CFRunLoopTimerCreateWithHandler(CFAllocatorRef allocator, CFAbsoluteTime fireDate, CFTimeInterval interval, CFOptionFlags flags, CFIndex order, void (^block) (id timer)) { + NSLog(@"🤔 CFRunLoopTimerCreateWithHandler"); + + // What is this doing? We don't seem to be creating a trampoline here - I feel like we should be? return (__bridge_retained CFRunLoopTimerRef)[[NSTimer alloc] initWithFireDate:CFBridgingRelease(CFDateCreate(allocator, fireDate)) interval:interval repeats:interval > 0 block:block]; } From 2100b7b70b8c856348221dd75b3a4a80000a9cf2 Mon Sep 17 00:00:00 2001 From: Hayden Ball Date: Sat, 16 Apr 2022 18:14:36 +0100 Subject: [PATCH 04/11] fix(NSTimer+DTXSpy): Invalidate timers before untracking (and releasing) TimerTrampolines --- DetoxSync/DetoxSync/Spies/NSTimer+DTXSpy.m | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/DetoxSync/DetoxSync/Spies/NSTimer+DTXSpy.m b/DetoxSync/DetoxSync/Spies/NSTimer+DTXSpy.m index 4074462..3aab307 100644 --- a/DetoxSync/DetoxSync/Spies/NSTimer+DTXSpy.m +++ b/DetoxSync/DetoxSync/Spies/NSTimer+DTXSpy.m @@ -97,9 +97,9 @@ void __detox_sync_CFRunLoopRemoveTimer(CFRunLoopRef rl, CFRunLoopTimerRef timer, // NSLog(@"🤦‍♂️ removeTimer: %@", NS(timer)); id trampoline = [DTXTimerSyncResource existingTimerProxyWithTimer:NS(timer)]; - [trampoline untrack]; - __orig_CFRunLoopRemoveTimer(rl, timer, mode); + + [trampoline untrack]; } static void (*__orig_CFRunLoopTimerInvalidate)(CFRunLoopTimerRef timer); @@ -108,9 +108,9 @@ void __detox_sync_CFRunLoopTimerInvalidate(CFRunLoopTimerRef timer) // NSLog(@"🤦‍♂️ invalidate: %@", NS(timer)); id trampoline = [DTXTimerSyncResource existingTimerProxyWithTimer:NS(timer)]; - [trampoline untrack]; - __orig_CFRunLoopTimerInvalidate(timer); + + [trampoline untrack]; } static void (*__orig___NSCFTimer_invalidate)(NSTimer* timer); @@ -119,9 +119,9 @@ void __detox_sync___NSCFTimer_invalidate(NSTimer* timer) // NSLog(@"🤦‍♂️ invalidate: %@", timer); id trampoline = [DTXTimerSyncResource existingTimerProxyWithTimer:timer]; - [trampoline untrack]; - __orig___NSCFTimer_invalidate(timer); + + [trampoline untrack]; } From b5677c73ea29e986ed29d4292a004f8a3642e15a Mon Sep 17 00:00:00 2001 From: Hayden Ball Date: Sat, 16 Apr 2022 18:15:57 +0100 Subject: [PATCH 05/11] fix(NSTimer+DTXSpy): Tidy dealloc tracking for NSTimers --- DetoxSync/DetoxSync/Spies/NSTimer+DTXSpy.m | 9 +++++++ .../SyncResources/DTXTimerSyncResource.m | 26 +++++-------------- .../DetoxSync/Utils/_DTXTimerTrampoline.m | 2 +- 3 files changed, 16 insertions(+), 21 deletions(-) diff --git a/DetoxSync/DetoxSync/Spies/NSTimer+DTXSpy.m b/DetoxSync/DetoxSync/Spies/NSTimer+DTXSpy.m index 3aab307..019da0f 100644 --- a/DetoxSync/DetoxSync/Spies/NSTimer+DTXSpy.m +++ b/DetoxSync/DetoxSync/Spies/NSTimer+DTXSpy.m @@ -124,6 +124,15 @@ void __detox_sync___NSCFTimer_invalidate(NSTimer* timer) [trampoline untrack]; } +- (void)dealloc +{ + id trampoline = [DTXTimerSyncResource existingTimerProxyWithTimer:self]; + + if(trampoline) { + NSLog(@"🤦‍♂️ dealloc, but trampoline was still active: %@", self); + [trampoline untrack]; + } +} + (void)load { diff --git a/DetoxSync/DetoxSync/SyncResources/DTXTimerSyncResource.m b/DetoxSync/DetoxSync/SyncResources/DTXTimerSyncResource.m index d7ab95e..9347ffb 100644 --- a/DetoxSync/DetoxSync/SyncResources/DTXTimerSyncResource.m +++ b/DetoxSync/DetoxSync/SyncResources/DTXTimerSyncResource.m @@ -86,30 +86,16 @@ + (instancetype)sharedInstance shared = [DTXTimerSyncResource new]; [DTXSyncManager registerSyncResource:shared]; }); - - return shared; -} -/// Ugly hack for rare occasions where NSTimer gets released, but its associated objects are not released. -static NSUInteger _DTXCleanTimersAndReturnCount(NSMutableSet* _timers, NSMutableArray* eventIdentifiers) -{ - for (_DTXTimerTrampoline* trampoline in _timers.copy) { - if(trampoline.isDead) - { - [eventIdentifiers addObject:_DTXStringReturningBlock([NSString stringWithFormat:@"%p", trampoline])]; - [_timers removeObject:trampoline]; - } - } - - return _timers.count; + return shared; } - (void)clearTimerTrampolinesForCFRunLoop:(CFRunLoopRef)cfRunLoop { __block NSMutableArray* eventIdentifiers = [NSMutableArray new]; - + [self performMultipleUpdateBlock:^{ - return _DTXCleanTimersAndReturnCount(_timers, eventIdentifiers); + return _timers.count; } eventIdentifiers:_DTXObjectReturningBlock(eventIdentifiers) eventDescriptions:nil objectDescriptions:nil @@ -131,7 +117,7 @@ - (void)trackTimerTrampoline:(_DTXTimerTrampoline *)trampoline trampoline.jsonDescription])]; [_timers addObject:trampoline]; - return _DTXCleanTimersAndReturnCount(_timers, eventIdentifiers); + return _timers.count; } eventIdentifiers:_DTXObjectReturningBlock(eventIdentifiers) eventDescriptions:_DTXObjectReturningBlock(eventDescriptions) @@ -142,11 +128,11 @@ - (void)trackTimerTrampoline:(_DTXTimerTrampoline *)trampoline - (void)untrackTimerTrampoline:(_DTXTimerTrampoline *)trampoline { __block NSMutableArray* eventIdentifiers = [NSMutableArray new]; - + [self performMultipleUpdateBlock:^{ [eventIdentifiers addObject:_DTXStringReturningBlock([NSString stringWithFormat:@"%p", trampoline])]; [_timers removeObject:trampoline]; - return _DTXCleanTimersAndReturnCount(_timers, eventIdentifiers); + return _timers.count; } eventIdentifiers:_DTXObjectReturningBlock(eventIdentifiers) eventDescriptions:nil objectDescriptions:nil diff --git a/DetoxSync/DetoxSync/Utils/_DTXTimerTrampoline.m b/DetoxSync/DetoxSync/Utils/_DTXTimerTrampoline.m index 297b439..fcf13df 100644 --- a/DetoxSync/DetoxSync/Utils/_DTXTimerTrampoline.m +++ b/DetoxSync/DetoxSync/Utils/_DTXTimerTrampoline.m @@ -86,7 +86,7 @@ - (BOOL)isDead - (void)dealloc { - [self untrack]; + NSLog(@"🤦‍♂️ trampoline dealloc: %@ (tracking: %d)", self, _tracking); objc_setAssociatedObject(_timer, __DTXTimerTrampolineKey, nil, OBJC_ASSOCIATION_RETAIN); } From 716e2a7ad0c8f3ad5027aac9c3d276f4b93f1965 Mon Sep 17 00:00:00 2001 From: Hayden Ball Date: Sat, 16 Apr 2022 18:55:06 +0100 Subject: [PATCH 06/11] refactor(DTXUISyncResource): Reenable IMPLICIT_RETAIN_SELF and fix issues --- DetoxSync/DetoxSync.xcodeproj/project.pbxproj | 2 -- .../SyncResources/DTXUISyncResource.m | 28 +++++++++---------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/DetoxSync/DetoxSync.xcodeproj/project.pbxproj b/DetoxSync/DetoxSync.xcodeproj/project.pbxproj index 2f9402d..4fa0b69 100644 --- a/DetoxSync/DetoxSync.xcodeproj/project.pbxproj +++ b/DetoxSync/DetoxSync.xcodeproj/project.pbxproj @@ -1224,7 +1224,6 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = NO; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = NO; CODE_SIGN_STYLE = Automatic; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; @@ -1255,7 +1254,6 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = NO; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = NO; CODE_SIGN_STYLE = Automatic; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; diff --git a/DetoxSync/DetoxSync/SyncResources/DTXUISyncResource.m b/DetoxSync/DetoxSync/SyncResources/DTXUISyncResource.m index b69d8d4..cc22f9e 100644 --- a/DetoxSync/DetoxSync/SyncResources/DTXUISyncResource.m +++ b/DetoxSync/DetoxSync/SyncResources/DTXUISyncResource.m @@ -113,45 +113,45 @@ - (void)_untrackForParam:(NSUInteger*)param eventIdentifier:(NSString*(NS_NOESCA - (void)trackViewNeedsLayout:(UIView *)view { NSString* identifier = [self _trackForParam:&_viewNeedsLayoutCount eventDescription:_DTXStringReturningBlock(@"View Layout") objectDescription:_DTXStringReturningBlock(view.__detox_sync_safeDescription)]; - + __detox_sync_orig_dispatch_async(dispatch_get_main_queue(), ^ { - [self _untrackForParam:&_viewNeedsLayoutCount eventIdentifier:_DTXStringReturningBlock(identifier)]; + [self _untrackForParam:&self->_viewNeedsLayoutCount eventIdentifier:_DTXStringReturningBlock(identifier)]; }); } - (void)trackViewNeedsDisplay:(UIView *)view { NSString* identifier = [self _trackForParam:&_viewNeedsDisplayCount eventDescription:_DTXStringReturningBlock(@"View Display") objectDescription:_DTXStringReturningBlock(view.__detox_sync_safeDescription)]; - + __detox_sync_orig_dispatch_async(dispatch_get_main_queue(), ^ { - [self _untrackForParam:&_viewNeedsDisplayCount eventIdentifier:_DTXStringReturningBlock(identifier)]; + [self _untrackForParam:&self->_viewNeedsDisplayCount eventIdentifier:_DTXStringReturningBlock(identifier)]; }); } - (void)trackLayerNeedsLayout:(CALayer *)layer { NSString* identifier = [self _trackForParam:&_layerNeedsLayoutCount eventDescription:_DTXStringReturningBlock(@"Layer Layout") objectDescription:_DTXStringReturningBlock(layer.description)]; - + __detox_sync_orig_dispatch_async(dispatch_get_main_queue(), ^ { - [self _untrackForParam:&_layerNeedsLayoutCount eventIdentifier:_DTXStringReturningBlock(identifier)]; + [self _untrackForParam:&self->_layerNeedsLayoutCount eventIdentifier:_DTXStringReturningBlock(identifier)]; }); } - (void)trackLayerNeedsDisplay:(CALayer *)layer { NSString* identifier = [self _trackForParam:&_layerNeedsDisplayCount eventDescription:_DTXStringReturningBlock(@"Layer Display") objectDescription:_DTXStringReturningBlock(layer.description)]; - + __detox_sync_orig_dispatch_async(dispatch_get_main_queue(), ^ { - [self _untrackForParam:&_layerNeedsDisplayCount eventIdentifier:_DTXStringReturningBlock(identifier)]; + [self _untrackForParam:&self->_layerNeedsDisplayCount eventIdentifier:_DTXStringReturningBlock(identifier)]; }); } - (void)trackLayerPendingAnimation:(CALayer*)layer { NSString* identifier = [self _trackForParam:&_layerPendingAnimationCount eventDescription:_DTXStringReturningBlock(@"Layer Pending Animation") objectDescription:_DTXStringReturningBlock(layer.description)]; - + __detox_sync_orig_dispatch_async(dispatch_get_main_queue(), ^ { - [self _untrackForParam:&_layerPendingAnimationCount eventIdentifier:_DTXStringReturningBlock(identifier)]; + [self _untrackForParam:&self->_layerPendingAnimationCount eventIdentifier:_DTXStringReturningBlock(identifier)]; }); } @@ -160,9 +160,9 @@ - (void)trackViewControllerWillAppear:(UIViewController *)vc if(vc.transitionCoordinator) { NSString* identifier = [self _trackForParam:&_viewControllerWillAppearCount eventDescription:_DTXStringReturningBlock(@"View Layout") objectDescription:_DTXStringReturningBlock(vc.description)]; - + [vc.transitionCoordinator animateAlongsideTransition:nil completion:^(id _Nonnull context) { - [self _untrackForParam:&_viewControllerWillAppearCount eventIdentifier:_DTXStringReturningBlock(identifier)]; + [self _untrackForParam:&self->_viewControllerWillAppearCount eventIdentifier:_DTXStringReturningBlock(identifier)]; }]; } } @@ -172,9 +172,9 @@ - (void)trackViewControllerWillDisappear:(UIViewController *)vc if(vc.transitionCoordinator) { NSString* identifier = [self _trackForParam:&_viewControllerWillDisappearCount eventDescription:_DTXStringReturningBlock(@"View Layout") objectDescription:_DTXStringReturningBlock(vc.description)]; - + [vc.transitionCoordinator animateAlongsideTransition:nil completion:^(id _Nonnull context) { - [self _untrackForParam:&_viewControllerWillDisappearCount eventIdentifier:_DTXStringReturningBlock(identifier)]; + [self _untrackForParam:&self->_viewControllerWillDisappearCount eventIdentifier:_DTXStringReturningBlock(identifier)]; }]; } } From a4aa2d580fa78acc3b0f0bc3c0c034281cfa645c Mon Sep 17 00:00:00 2001 From: Hayden Ball Date: Mon, 18 Apr 2022 11:23:08 +0100 Subject: [PATCH 07/11] fix(_DTXTimerTrampoline): Correct removal of display link associated object --- DetoxSync/DetoxSync/Utils/_DTXTimerTrampoline.m | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/DetoxSync/DetoxSync/Utils/_DTXTimerTrampoline.m b/DetoxSync/DetoxSync/Utils/_DTXTimerTrampoline.m index fcf13df..a837bde 100644 --- a/DetoxSync/DetoxSync/Utils/_DTXTimerTrampoline.m +++ b/DetoxSync/DetoxSync/Utils/_DTXTimerTrampoline.m @@ -88,7 +88,15 @@ - (void)dealloc { NSLog(@"🤦‍♂️ trampoline dealloc: %@ (tracking: %d)", self, _tracking); - objc_setAssociatedObject(_timer, __DTXTimerTrampolineKey, nil, OBJC_ASSOCIATION_RETAIN); + if(_timer) + { + objc_setAssociatedObject(_timer, __DTXTimerTrampolineKey, nil, OBJC_ASSOCIATION_ASSIGN); + } + + if(_displayLink) + { + objc_setAssociatedObject(_displayLink, __DTXTimerTrampolineKey, nil, OBJC_ASSOCIATION_ASSIGN); + } } - (void)setTimer:(NSTimer*)timer @@ -105,7 +113,7 @@ - (void)setTimer:(NSTimer*)timer - (void)setDisplayLink:(CADisplayLink*)displayLink { _displayLink = displayLink; - objc_setAssociatedObject(_displayLink, __DTXTimerTrampolineKey, self, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + objc_setAssociatedObject(_displayLink, __DTXTimerTrampolineKey, self, OBJC_ASSOCIATION_RETAIN); #if DEBUG _history = [NSString stringWithFormat:@"%@\n%@", _history, [displayLink debugDescription]]; From ef928905018796f63291bc4d054120e310b8f53a Mon Sep 17 00:00:00 2001 From: Hayden Ball Date: Mon, 18 Apr 2022 11:24:16 +0100 Subject: [PATCH 08/11] refactor(_DTXTimerTrampoline): Remove unused _timerDescription var --- DetoxSync/DetoxSync/Utils/_DTXTimerTrampoline.m | 2 -- 1 file changed, 2 deletions(-) diff --git a/DetoxSync/DetoxSync/Utils/_DTXTimerTrampoline.m b/DetoxSync/DetoxSync/Utils/_DTXTimerTrampoline.m index a837bde..a62e067 100644 --- a/DetoxSync/DetoxSync/Utils/_DTXTimerTrampoline.m +++ b/DetoxSync/DetoxSync/Utils/_DTXTimerTrampoline.m @@ -21,7 +21,6 @@ @implementation _DTXTimerTrampoline __weak NSTimer* _timer; CFRunLoopTimerCallBack _callback; CFRunLoopRef _runLoop; - NSString* _timerDescription; NSTimeInterval _timeUntilFire; //CADisplayLink @@ -102,7 +101,6 @@ - (void)dealloc - (void)setTimer:(NSTimer*)timer { _timer = timer; - _timerDescription = [[timer debugDescription] copy]; objc_setAssociatedObject(timer, __DTXTimerTrampolineKey, self, OBJC_ASSOCIATION_RETAIN); #if DEBUG From 8b9d012ee9c8dc3d44e3a1e48e07109457db355b Mon Sep 17 00:00:00 2001 From: Hayden Ball Date: Mon, 18 Apr 2022 16:31:08 +0100 Subject: [PATCH 09/11] fix(DTXTimerTrampoline): HACK: Only fire timer callback if timer is defined --- DetoxSync/DetoxSync/Utils/_DTXTimerTrampoline.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DetoxSync/DetoxSync/Utils/_DTXTimerTrampoline.m b/DetoxSync/DetoxSync/Utils/_DTXTimerTrampoline.m index a62e067..347999f 100644 --- a/DetoxSync/DetoxSync/Utils/_DTXTimerTrampoline.m +++ b/DetoxSync/DetoxSync/Utils/_DTXTimerTrampoline.m @@ -120,14 +120,14 @@ - (void)setDisplayLink:(CADisplayLink*)displayLink - (void)fire { - if(_callback) + if(_timer && _callback) { CFRunLoopTimerContext ctx; CFRunLoopTimerGetContext((__bridge CFRunLoopTimerRef)_timer, &ctx); _callback((__bridge CFRunLoopTimerRef)_timer, ctx.info); } - if(_target && _sel) { + if(_timer && _target && _sel) { IMP impl = [_target methodForSelector:_sel]; void (*func)(id, SEL, NSTimer*) = (void *)impl; func(_target, _sel, _timer); From ee5c6a0d6b3d7c76a11b1e83771ee551c3c72550 Mon Sep 17 00:00:00 2001 From: Hayden Ball Date: Mon, 18 Apr 2022 16:40:45 +0100 Subject: [PATCH 10/11] fixup! fix(_DTXTimerTrampoline): Correct removal of display link associated object --- .../DetoxSync/Utils/_DTXTimerTrampoline.m | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/DetoxSync/DetoxSync/Utils/_DTXTimerTrampoline.m b/DetoxSync/DetoxSync/Utils/_DTXTimerTrampoline.m index 347999f..e2bb192 100644 --- a/DetoxSync/DetoxSync/Utils/_DTXTimerTrampoline.m +++ b/DetoxSync/DetoxSync/Utils/_DTXTimerTrampoline.m @@ -87,15 +87,15 @@ - (void)dealloc { NSLog(@"🤦‍♂️ trampoline dealloc: %@ (tracking: %d)", self, _tracking); - if(_timer) - { - objc_setAssociatedObject(_timer, __DTXTimerTrampolineKey, nil, OBJC_ASSOCIATION_ASSIGN); - } - - if(_displayLink) - { - objc_setAssociatedObject(_displayLink, __DTXTimerTrampolineKey, nil, OBJC_ASSOCIATION_ASSIGN); - } + if(_timer) + { + objc_setAssociatedObject(_timer, __DTXTimerTrampolineKey, nil, OBJC_ASSOCIATION_ASSIGN); + } + + if(_displayLink) + { + objc_setAssociatedObject(_displayLink, __DTXTimerTrampolineKey, nil, OBJC_ASSOCIATION_ASSIGN); + } } - (void)setTimer:(NSTimer*)timer From f2b47c5ce068356d91e238df5c3faf6baa19cb42 Mon Sep 17 00:00:00 2001 From: Hayden Ball Date: Mon, 18 Apr 2022 16:41:08 +0100 Subject: [PATCH 11/11] fix(DTXTimerTrampoline): HACK: throw if no implementation for selector --- DetoxSync/DetoxSync/Utils/_DTXTimerTrampoline.m | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/DetoxSync/DetoxSync/Utils/_DTXTimerTrampoline.m b/DetoxSync/DetoxSync/Utils/_DTXTimerTrampoline.m index e2bb192..da70c69 100644 --- a/DetoxSync/DetoxSync/Utils/_DTXTimerTrampoline.m +++ b/DetoxSync/DetoxSync/Utils/_DTXTimerTrampoline.m @@ -129,6 +129,11 @@ - (void)fire if(_timer && _target && _sel) { IMP impl = [_target methodForSelector:_sel]; + + if(!impl) { + @throw @"☠️ attempted to call a selector but couldn't find the implementation!"; + } + void (*func)(id, SEL, NSTimer*) = (void *)impl; func(_target, _sel, _timer); }