NSTimer使用不当引发的内存泄漏问题

时间:2021-08-25 19:58:10

NSTimer可以用来执行一些定时任务,比较常用的方法就是:

+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)yesOrNo;

可是,仔细看官方文档中对于参数target的说明,可以看到这样一段:

target

The object to which to send the message specified by aSelector when the timer fires. The timer maintains a strong reference to this object until it (the timer) is invalidated.

也就是说,NSTimer会强引用target.

那么如果我们按照通常的用法,在view controller中创建一个timer

self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timerFireMethod:) userInfo:nil repeats:YES];

就会带来循环引用,viewController的dealloc()方法不会正确调用,从而导致内存泄漏。

所以正确的做法,如果是在view controller中持有了NSTimer的对象,那么需要确保在view controller关闭之前,执行如下方法:

 [timer invalidate];

有些人推荐是在viewDidDisappear的时候调用这个方法,但在部分业务逻辑中,跳转到下一个页面的时候并不是一定需要停止这个定时器的;所以需要根据自己的需要来调整。

另外,多说一句,看到有些代码中使用timer的时候,定义的selector都没有定义参数的,然后根据官方文档,

The selector should have the following signature: timerFireMethod: (including a colon to indicate that the method takes an argument). The timer passes itself as the argument, thus the method would adopt the following pattern:

- (void)timerFireMethod:(NSTimer *)timer;

也就是说,这个selelctor实际上是需要带上timer作为参数的。

联想到上一篇谈到NSNotificationCenter 的文章,

- (void)addObserver:(id)observer selector:(SEL)aSelector name:(NSString *)aName object:(id)anObject;

里面对于selector其实也说得很清楚,也是需要带上一个参数而且只能带上一个NSNotification的对象作为参数的.

notificationSelector

Selector that specifies the message the receiver sends notificationObserver to notify it of the notification posting. The method specified by notificationSelector must have one and only one argument (an instance of NSNotification).

The End.