计时器需要和“运行循环”相关联,如下:
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;
这个问题可以用块解决。
这样写后,最后一个EOCClass的引用失效,计时器也会被回收。
总结:
1.调用invalidate方法可以令计时器失效,一次性计时器完成任务后也会失效。
2.反复执行任务的计时器容易引入保留环。
3.可以扩充NSTimer的功能,用块打破保留环。
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;
用这个方法创建计时器,会在指定时间间隔后执行任务,直到开发者手动关闭。target和selector表示计时器将会在哪个对象上调用哪个方法。计时器会保留目标对象,自身失效时再释放对象。invalidate会使计时器失效。
@interface EOCClass : NSObject
-(void)startPolling;
-(void)stopPolling;
@end
@implementation EOCClass {
NSTimer *_pollTimer;
}
-(id)init{
return [super init];
}
-(void)dealloc{
[_pollTimer invalidate];
}
-(void)stopPolling{
[_pollTimer invalidate];
_pollTimer = nil;
}
-(void)startPolling{
_pollTimer = [NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:@selector(p_doPoll) userInfo:nil repeats:YES];
}
-(void)p_doPoll{
//do something
}
@end
计时器会保留self,因为计时器是实例变量,所以self也会保留计时器。打破保留环,要么让系统回收计时器,要么让计时器失效。这种通过调用某个方法避免内存泄漏的方法并不是很好。这个问题可以用块解决。
@interface NSTimer (EOCBlocksSupport)
+(NSTimer *)eoc_scheduledTimerWithTimeInterval:(NSTimeInterval)interval block:(void(^)())block repeats:(BOOL)repeats;
@end
@implementation NSTimer (EOCBlocksSupport)
+(NSTimer *)eoc_scheduledTimerWithTimeInterval:(NSTimeInterval)interval block:(void (^)())block repeats:(BOOL)repeats {
return [self scheduledTimerWithTimeInterval:interval target:self selector:@selector(eoc_blockInvoke:) userInfo:[block copy] repeats:repeats];
}
+(void)eoc_blockInvoke:(NSTimer *)timer {
void (^block)() = timer.userInfo;
if (block) {
block();
}
}
@end
将计时器所要执行的任务封装成块,用usaerInfo传进去,传入的块通过copy拷贝到堆上,避免需要使用的时候失效。-(void)startPolling{
_pollTimer = [NSTimer scheduledTimerWithTimeInterval:5.0 block:([self p_doPoll];) repeats:YES];
}
代码本身还是有保留环的,self保留了计时器,计时器保留了block,block保留了self。使用弱引用可以打破保留环。-(void)startPolling{
__weak EOCClass *weakSelf = self;
_pollTimer = [NSTimer scheduledTimerWithTimeInterval:5.0 block:(
EOCClass *strongSelf = weakSelf;
[strongSelf p_doPoll];) repeats:YES];
}
先定义了一个弱引用weakSelf,等块捕获weakSelf后立即变为强引用strongSelf保证执行期间继续存活。这样写后,最后一个EOCClass的引用失效,计时器也会被回收。
总结:
1.调用invalidate方法可以令计时器失效,一次性计时器完成任务后也会失效。
2.反复执行任务的计时器容易引入保留环。
3.可以扩充NSTimer的功能,用块打破保留环。