服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - IOS - iOS中的NSTimer定时器的初步使用解析

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

2021-01-18 13:26李刚 IOS

这篇文章主要介绍了iOS中的NSTimer定时器的初步使用解析,通过例子简单讲解了NSTimer的输出与停止的方法,需要的朋友可以参考下

创建一个定时器(nstimer)

?
1
2
3
4
5
6
7
8
9
- (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上面.

?
1
2
3
4
5
6
7
8
9
10
11
- (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上的数字也就无法更新。

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

修改nstimer的run loop

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

?
1
[[nsrunloop currentrunloop] addtimer:timer formode:uitrackingrunloopmode];

或者

?
1
[[nsrunloop currentrunloop] addtimer:timer formode:nsrunloopcommonmodes];

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

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

 

fire

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@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 的方法:

?
1
2
3
4
-(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 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 按钮:

?
1
2
3
- (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 方法。
  • 嗯…

延伸 · 阅读

精彩推荐
  • IOSiOS中tableview 两级cell的展开与收回的示例代码

    iOS中tableview 两级cell的展开与收回的示例代码

    本篇文章主要介绍了iOS中tableview 两级cell的展开与收回的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...

    J_Kang3862021-04-22
  • IOSiOS通过逆向理解Block的内存模型

    iOS通过逆向理解Block的内存模型

    自从对 iOS 的逆向初窥门径后,我也经常通过它来分析一些比较大的应用,参考一下这些应用中某些功能的实现。这个探索的过程乐趣多多,不仅能满足自...

    Swiftyper12832021-03-03
  • IOSIOS 屏幕适配方案实现缩放window的示例代码

    IOS 屏幕适配方案实现缩放window的示例代码

    这篇文章主要介绍了IOS 屏幕适配方案实现缩放window的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要...

    xiari5772021-06-01
  • IOSiOS 雷达效果实例详解

    iOS 雷达效果实例详解

    这篇文章主要介绍了iOS 雷达效果实例详解的相关资料,需要的朋友可以参考下...

    SimpleWorld11022021-01-28
  • IOS解析iOS开发中的FirstResponder第一响应对象

    解析iOS开发中的FirstResponder第一响应对象

    这篇文章主要介绍了解析iOS开发中的FirstResponder第一响应对象,包括View的FirstResponder的释放问题,需要的朋友可以参考下...

    一片枫叶4662020-12-25
  • IOSIOS开发之字典转字符串的实例详解

    IOS开发之字典转字符串的实例详解

    这篇文章主要介绍了IOS开发之字典转字符串的实例详解的相关资料,希望通过本文能帮助到大家,让大家掌握这样的方法,需要的朋友可以参考下...

    苦练内功5832021-04-01
  • IOS关于iOS自适应cell行高的那些事儿

    关于iOS自适应cell行高的那些事儿

    这篇文章主要给大家介绍了关于iOS自适应cell行高的那些事儿,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的...

    daisy6092021-05-17
  • IOSiOS布局渲染之UIView方法的调用时机详解

    iOS布局渲染之UIView方法的调用时机详解

    在你刚开始开发 iOS 应用时,最难避免或者是调试的就是和布局相关的问题,下面这篇文章主要给大家介绍了关于iOS布局渲染之UIView方法调用时机的相关资料...

    windtersharp7642021-05-04