In my app I have a following piece of code:
__weak __typeof(self)weakSelf = self;
_pingTimer = [NSTimer scheduledTimerWithTimeInterval:5.0
repeats:YES
block:^(NSTimer * _Nonnull timer)
{
__strong __typeof(weakSelf)strongSelf = weakSelf;
[strongSelf pingWithBlock:nil];
}];
this works perfectly in iOS 10+, but I need the app to support iOS 9 as well. So I needed to provide a method that would work for both.
I tried this:
__weak __typeof(self)weakSelf = self;
_pingTimer = [NSTimer scheduledTimerWithTimeInterval:5.0
target:weakSelf
selector:@selector(pingWithBlock:)
userInfo:nil
repeats:YES];
pingWithBlock method is defined in the same class, it's an instance method.
But this doesn't seem to work, meaning I get a bad memory access crash.
If anyone has any suggestions it will be highly appreciated.
EDIT: thanks to @dgatwood explanations code below fixes the issue
- (void)autoPing
{
_pingTimer = [NSTimer scheduledTimerWithTimeInterval:self.autoCheckInterval
target:self
selector:@selector(pingWithBlock)
userInfo:nil
repeats:YES];
}
-(void)pingWithBlock
{
[self pingWithBlock:nil];
}
This is kind of odd. NSTimer retains its target. Maybe that doesn't happen in this case because of the __weak
, but I thought it did anyway. *shrugs*
Either way, this sounds like a multithreading race condition:
The best fix is to let the timer retain the target object (by removing all the weakSelf
stuff). If the timer is a repeating timer, provide a method to allow the code that disposes of the enclosing object to cancel that timer, and be careful to always call it.