当前位置: 首页 > 编程笔记 >

iOS中的NSTimer定时器的初步使用解析

子车轶
2023-03-14
本文向大家介绍iOS中的NSTimer定时器的初步使用解析,包括了iOS中的NSTimer定时器的初步使用解析的使用技巧和注意事项,需要的朋友参考一下

创建一个定时器(NSTimer)

- (void)viewDidLoad {
  [super viewDidLoad];
  [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(actionTimer:) userInfo:nil repeats:YES];
}

- (void)actionTimer:(NSTimer *)timer
{

}

NSTimer默认运行在default mode下,default mode几乎包括所有输入源(除NSConnection) NSDefaultRunLoopMode模式。

actionTimer方法会每隔1s中被调用一次。NSTimer使用起来是不是非常简单。这是NSTimer比较初级的应用。

当主界面被滑动时NSTimer失效了

主界面被滑动是什么意思呢?就是说主界面有UITableView或者UIScrollView,滑动UITableView或者UIScrollView。这个时候NSTimer失效了。

我们来写一个demo,在一个有UITableView的UIViewController上启动定时器,每1s数字加1,并将这个数字显示在UILabel上面.

- (void)viewDidLoad {
  [super viewDidLoad];
  [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(actionTimer:) userInfo:nil repeats:YES];
}

- (void)actionTimer:(NSTimer *)timer
{
  self.number++;
  self.label.text = [NSString stringWithFormat:@"%d",self.number];
  NSLog(@"%d",self.number);
}

关于UITableView和UILabel的创建我省去了。详细的代码可以点击这里下载:iOSStrongDemo,iOSStrongDemo我会不断更新,大家在github上star一下。

这样当用户在拖动UITableView处于UITrackingRunLoopMode时,NSTimer就失效了,不能fire。self.label上的数字也就无法更新。

修改NSTimer的run loop

解决方法就是将其加入到UITrackingRunLoopMode模式或NSRunLoopCommonModes模式中。

[[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];

或者

[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

NSRunLoopCommonModes:是一个模式集合,当绑定一个事件源到这个模式集合的时候就相当于绑定到了集合内的每一个模式。

fire

我们先用 NSTimer 来做个简单的计时器,每隔5秒钟在控制台输出 Fire 。比较想当然的做法是这样的:

@interface DetailViewController ()
@property (nonatomic, weak) NSTimer *timer;
@end

@implementation DetailViewController
- (IBAction)fireButtonPressed:(id)sender {
  _timer = [NSTimer scheduledTimerWithTimeInterval:3.0f
                       target:self
                      selector:@selector(timerFire:)
                      userInfo:nil
                       repeats:YES];
  [_timer fire];
}

-(void)timerFire:(id)userinfo {
  NSLog(@"Fire");
}
@end

运行之后确实在控制台每隔3秒钟输出一次 Fire ,然而当我们从这个界面跳转到其他界面的时候却发现:控制台还在源源不断的输出着 Fire 。看来 Timer 并没有停止。

invalidate

既然没有停止,那我们在 DemoViewController 的 dealloc 里加上 invalidate 的方法:

-(void)dealloc {
  [_timer invalidate];
  NSLog(@"%@ dealloc", NSStringFromClass([self class]));
}

再次运行,还是没有停止。原因是 Timer 添加到 Runloop 的时候,会被 Runloop 强引用:

Note in particular that run loops maintain strong references to their timers, so you don't have to maintain your own strong reference to a timer after you have added it to a run loop.
然后 Timer 又会有一个对 Target 的强引用(也就是 self ):

Target is the html" target="_blank">object to which to send the message specified by aSelector when the timer fires. The timer maintains a strong reference to target until it (the timer) is invalidated.
也就是说 NSTimer 强引用了 self ,导致 self 一直不能被释放掉,所以也就走不到 self 的 dealloc 里。

既然如此,那我们可以再加个 invalidate 按钮:

- (IBAction)invalidateButtonPressed:(id)sender {
  [_timer invalidate];
}

嗯这样就可以了。(在 SOF 上有人说该在 invalidate 之后执行 _timer = nil ,未能理解为什么,如果你知道原因可以告诉我:)

在 invalidate 方法的文档里还有这这样一段话:

You must send this message from the thread on which the timer was installed. If you send this message from another thread, the input source associated with the timer may not be removed from its run loop, which could prevent the thread from exiting properly.
NSTimer 在哪个线程创建就要在哪个线程停止,否则会导致资源不能被正确的释放。看起来各种坑还不少。

dealloc

那么问题来了:如果我就是想让这个 NSTimer 一直输出,直到 DemoViewController 销毁了才停止,我该如何让它停止呢?

  • NSTimer 被 Runloop 强引用了,如果要释放就要调用 invalidate 方法。
  • 但是我想在 DemoViewController 的 dealloc 里调用 invalidate 方法,但是 self 被 NSTimer 强引用了。
  • 所以我还是要释放 NSTimer 先,然而不调用 invalidate 方法就不能释放它。
  • 然而你不进入到 dealloc 方法里我又不能调用 invalidate 方法。
  • 嗯…


 类似资料:
  • 本文向大家介绍IOS 中NSTimer定时器的使用,包括了IOS 中NSTimer定时器的使用的使用技巧和注意事项,需要的朋友参考一下 IOS 中NSTimer定时器的使用 NSTimery 定时器,主要用于进行定时执行指定方法,常用场景如:获取验证码的按钮倒计时;图片轮播定时。 1 使用注意事项: 1.1 倒计时时间间隔(时间单位是秒) 1.2 指定的执行方法 1.3 实现指定执行方法的对象 1

  • 本文向大家介绍iOS NSTimer循环引用的办法,包括了iOS NSTimer循环引用的办法的使用技巧和注意事项,需要的朋友参考一下 在当前控制器(ViewController)的view上添加了一个自定义的view(LXFTimerView), LXFTimerView在成功创建出来后添加了定时器NSTimer并加入RunLoop开始工作, 当在当前控制器里将LXFTimerView移除掉后,

  • 本文向大家介绍iOS NSTimer循环引用的几种解决办法,包括了iOS NSTimer循环引用的几种解决办法的使用技巧和注意事项,需要的朋友参考一下 发生场景 在 Controller B 中有一个 NSTimer 你创建了它,并挂载到 main runloop 然后退出 Controller B 的时候,忘记关掉 timer 了 Controller B 将不会释放,B 与 timer 循环引

  • 本文向大家介绍iOS如何巧妙解决NSTimer的循环引用详解,包括了iOS如何巧妙解决NSTimer的循环引用详解的使用技巧和注意事项,需要的朋友参考一下 一 发现问题 我们都知道NSTimer采用target-action的方式,通常target又是类本身,我们为了方便又把NSTimer声明为属性变量,这样就难免会造成循环引用(需要反复执行计时任务时,如果是单次的任务就不会造成循环引用)。 例如

  • 在命令行的shell提示符下键入python,启动解释器。现在输入print 'Hello World',然后按Enter键。你应该可以看到输出的单词Hello World。 对于Windows用户,只要你正确的设置了PATH变量,你应该可以从命令行启动解释器。或者你可以选择使用IDLE程序。IDLE是集成开发环境的缩写。点击开始->程序->Python 2.3->IDLE(Python GUI)

  • 问题内容: 在这种情况下,永远不会调用timerFunc()。我想念什么? 问题答案: 您可以创建一个计划的计时器,该计时器自动将其自身添加到运行循环并开始触发: 迅捷2 斯威夫特3,4,5 或者,您可以保留当前代码,并在准备就绪时将计时器添加到runloop中: 迅捷2 斯威夫特3,4,5