A completely different approach to the same problem with NSTimer
.
You want a free running non-interupted timer that will fire each 20seconds and should not leak, even if the target is deallocated. That is one of the cases when a NSProxy
comes into play very handy. It's just three more lines of code but safe.
Let's assume you have an NSObject
with an "updateMethod" you want to pass the invocation on.
@interface YourTargetObject : NSObject
-(void)updateMethod;
@end
The NSProxy
would look like.
@interface YourWeakDelegateProxy : NSProxy
-(instancetype)initWithTarget:(YourTargetObject*)target;
@property (nonatomic, weak) YourTargetObjectClass * target;
@end
The invocation in detail. We only pass a delegates pointer here and forward the invocation to the selector.
@implementation YourWeakDelegateProxy
-(instancetype)initWithTarget:(YourTargetObject*)target {
self.target = target;
return self;
}
-(NSMethodSignature *)methodSignatureForSelector:(SEL)selector {
return [_target methodSignatureForSelector:selector];
}
-(void)forwardInvocation:(NSInvocation *)invocation {
[invocation setTarget:_target];
[invocation invoke];
}
@end
now you can invoke a (possibly later not anymore existing) object with your timer somewhere in your class in the following way..
self.timer = [NSTimer
scheduledTimerWithTimeInterval:20.0
target:[[YourWeakDelegateProxy alloc] initWithTarget:self]
selector:@selector(updateMethod)
userInfo:nil
repeats:NO];
and as usually keeping an eye on the timers deallocation..
Actually ARC does that for you.. but still it would look like..
-(void)dealloc {
[_timer invalidate];
_timer = nil;
}
So now the timer is guaranteed to invoke on a new proxy.
The proxy forwards its invocation on the delegate. If the delegate (self) becomes invalid in between your 20 seconds nothing bad happens.
PS: reminder.. Each thread has at least one runloop but not each runloop does have its own thread, instead they sometime share one thread.