1、scrollView滾動(dòng)時(shí)NSTimer暫停的問(wèn)題
便利構(gòu)造方法 + (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;會(huì)將timer直接綁定到NSDefaultRunLoopMode,而在scrollView滾動(dòng)的時(shí)候處于UITrackingRunLoopMode下,是不會(huì)處理NSRunLoopDefaultMode的消息的,因此此時(shí)應(yīng)該手動(dòng)添加timer到NSRunLoopCommonModes下面。
timer = [NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:@selector(doSomething) userInfo:nil repeats:NO];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
2、UIView的NSTimer內(nèi)存釋放
如果你的View有一個(gè)property:
@property(nonatomic, strong) NSTimer *timer;
然后你初始化并執(zhí)行一個(gè)循環(huán)動(dòng)畫(huà)
- (void)start
{
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(handleTimer:) userInfo:nil repeats:YES];
}
-(void)handleTimer:(NSTimer *)theTimer
{
// 動(dòng)畫(huà)
}
你應(yīng)該知道NSTimer需要invalidate才能使得view能夠dealloc。但是這樣寫(xiě)是自欺欺人的做法:
- (void)stopTimer
{
[self.timer invalidate];
self.timer = nil;
}
- (void)dealloc
{
[self stopTimer];
}
你陷入了雞生蛋,蛋生雞的悖論中。。。你要view死,然后才invalidate,但是view非要等到你invalidate才能死啊!如果你又不想在外面顯示的調(diào)用stopTimer,那么這樣做比較合適,在view移除出視圖結(jié)構(gòu)的時(shí)候
- (void)willMoveToSuperview:(UIView *)newSuperview
{
if (!newSuperview)
{
[self stopTimer];
}
}
另外也可以參照《Effective Objective-C 2.0》書(shū)中的做法:采用block的方式,推薦用這種,ios 10中已經(jīng)提供了這個(gè)API了。
@interface NSTimer (OVExtension)
// 避免 timer 循環(huán)引用,自動(dòng)釋放
// ios 10 已經(jīng)有了這個(gè) api,但是 ios8 和 ios9 不支持
+ (instancetype)ov_scheduledTimerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)())block;
@end
@implementation NSTimer (OVExtension)
+ (instancetype)ov_scheduledTimerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)())block
{
return [self scheduledTimerWithTimeInterval:interval target:self selector:@selector(ov_blockInvoke:) userInfo:[block copy] repeats:repeats];
}
+ (void)ov_blockInvoke:(NSTimer *)timer
{
void (^block)() = timer.userInfo;
if (block) {
block();
}
}
@end