场景
在程序开发中经常会遇到计时器, 比如促销活动的倒计时,发送短信验证码过段时间才允许第二次发送、设置一段倒计时。
问题
这时会用到 下面这个api, scheduledTimerWithTimeInterval:target:selector:userInfo:repeats: API_AVAILABLE(ios(2.0))
, 这个api从ios 2.0就开始提供了,可以兼容较低版本的ios系统。可是由于Timer会保留target参数,所以这个api会比较容易造成循环引用。想象一下有一个自定义ViewController1,里边有个倒计时功能,很容易通过下边的代码实现:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
_timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(invokeTimer) userInfo:nil repeats:YES];
}
- (void)invokeTimer {
NSLog(@"%@", self);
}
- (void)dealloc
{
[_timer invalidate];
NSLog(@"%s", __FUNCTION__);
}
每过一秒钟触发一次,触发方法会输出log,在dealloc中将timer置为无效。看似天衣无缝,但实际上,从自定义ViewController1返回时,并不会调用dealloc,原因就是上文中提到的NSTimer对target的保留。这样就会造成ViewController1的内存泄漏了。
解决思路
利用像下边这样的类扩展,此时Timer的target 不再是自定义ViewController1
typedef void (^TimerHandler) (NSTimer *);
@interface NSTimer (HandleRetainTarget)
@end
@implementation NSTimer(HandleRetainTarget)
+ (NSTimer *)Eoc_timerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))handler {
return [NSTimer scheduledTimerWithTimeInterval:interval target:[self class] selector:@selector(repeatTimer:) userInfo:[handler copy] repeats:YES];
}
+ (void)repeatTimer:(NSTimer *)timer {
TimerHandler handler = timer.userInfo;
if (handler) {
handler(timer);
}
}
@end
调用示例
__weak typeof (self) weakself = self;
_timer = [NSTimer Eoc_timerWithTimeInterval:1.0 repeats:YES block:^(NSTimer *timer) {
[weakself invokeTimer];
}];
截图
点击Button -> 点击Back -> 查看log
! |
---|
今天的文章利用类扩展解决NSTimer会保留目标对象分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:http://bianchenghao.cn/18068.html