Skip to content

Commit

Permalink
Avoid crash due to iOS createTimer API change (wix#1710)
Browse files Browse the repository at this point in the history
* Handle createTimer API change

* Styling and use NSMethodSignature for cleaner API
  • Loading branch information
4-rodrigo-salazar authored and LeoNatan committed Oct 24, 2019
1 parent 1e5400d commit 57300d5
Showing 1 changed file with 46 additions and 29 deletions.
75 changes: 46 additions & 29 deletions detox/ios/Detox/WXJSTimerObservationIdlingResource.m
Original file line number Diff line number Diff line change
Expand Up @@ -119,39 +119,56 @@ - (instancetype)init
SEL createTimerSel = NSSelectorFromString(@"createTimer:duration:jsSchedulingTime:repeats:");
Method m = class_getInstanceMethod(cls, createTimerSel);

void (*orig_createTimer)(id, SEL, NSNumber*, NSTimeInterval, NSDate*, BOOL) = (void(*)(id, SEL, NSNumber*, NSTimeInterval, NSDate*, BOOL))method_getImplementation(m);
method_setImplementation(m, imp_implementationWithBlock(^(id _self, NSNumber* timerID, NSTimeInterval duration, NSDate* jsDate, BOOL repeats) {
__strong __typeof(weakSelf) strongSelf = weakSelf;

dispatch_sync(_timersObservationQueue, ^{
_WXJSTimingObservationWrapper* _observationWrapper = [strongSelf->_observations objectForKey:_self];

if(_observationWrapper == nil)
{
_observationWrapper = [[_WXJSTimingObservationWrapper alloc] initWithTimers:[_self valueForKey:@"_timers"]];
[_self setValue:_observationWrapper forKey:@"_timers"];
[strongSelf->_observations setObject:_observationWrapper forKey:_self];
}


if(duration > 0 && duration <= _durationThreshold && repeats == NO)
{
dtx_log_info(@"Observing timer: %@ d: %@ r: %@", timerID, @(duration), @(repeats));

[_observationWrapper addObservedTimer:timerID];
}
else
{
dtx_log_info(@"Ignoring timer: %@ failure reason: \"%@\"", timerID, [strongSelf failuireReasonForDuration:duration repeats:repeats]);
}
});

orig_createTimer(_self, createTimerSel, timerID, duration, jsDate, repeats);
}));
// Check if the createTimer interface is using doubles or NSObjects.
// Earlier versions of react native use NSObjects for the timer and
// date params, while later versions use doubles for these.
const char* timerArgType = [[cls instanceMethodSignatureForSelector:createTimerSel] getArgumentTypeAtIndex:2];
if (strncmp(timerArgType, "d", 1) == 0)
{
void (*orig_createTimer)(id, SEL, double, NSTimeInterval, double, BOOL) = (void*)method_getImplementation(m);
method_setImplementation(m, imp_implementationWithBlock(^(id _self, double timerID, NSTimeInterval duration, double jsDate, BOOL repeats) {
__strong __typeof(weakSelf) strongSelf = weakSelf;
[strongSelf attachObservation:_self timerID:@(timerID) duration:duration repeats:repeats];
orig_createTimer(_self, createTimerSel, timerID, duration, jsDate, repeats);
}));
}
else
{
void (*orig_createTimer)(id, SEL, NSNumber*, NSTimeInterval, NSDate*, BOOL) = (void*)method_getImplementation(m);
method_setImplementation(m, imp_implementationWithBlock(^(id _self, NSNumber* timerID, NSTimeInterval duration, NSDate* jsDate, BOOL repeats) {
__strong __typeof(weakSelf) strongSelf = weakSelf;
[strongSelf attachObservation:_self timerID:timerID duration:duration repeats:repeats];
orig_createTimer(_self, createTimerSel, timerID, duration, jsDate, repeats);
}));
}
}
return self;
}

- (void)attachObservation:(id)_self timerID:(NSNumber *)timerID duration:(NSTimeInterval)duration repeats:(BOOL)repeats
{
dispatch_sync(_timersObservationQueue, ^{
_WXJSTimingObservationWrapper* _observationWrapper = [self->_observations objectForKey:_self];

if(_observationWrapper == nil)
{
_observationWrapper = [[_WXJSTimingObservationWrapper alloc] initWithTimers:[_self valueForKey:@"_timers"]];
[_self setValue:_observationWrapper forKey:@"_timers"];
[self->_observations setObject:_observationWrapper forKey:_self];
}

if(duration > 0 && duration <= _durationThreshold && repeats == NO)
{
dtx_log_info(@"Observing timer: %@ d: %@ r: %@", timerID, @(duration), @(repeats));
[_observationWrapper addObservedTimer:timerID];
}
else
{
dtx_log_info(@"Ignoring timer: %@ failure reason: \"%@\"", timerID, [self failuireReasonForDuration:duration repeats:repeats]);
}
});
}

- (BOOL)isIdleNow
{
__block BOOL rv = YES;
Expand Down

0 comments on commit 57300d5

Please sign in to comment.