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

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开发技巧之状态栏字体颜色的设置方法

    iOS开发技巧之状态栏字体颜色的设置方法

    有时候我们需要根据不同的背景修改状态栏字体的颜色,下面这篇文章主要给大家介绍了关于iOS开发技巧之状态栏字体颜色的设置方法,文中通过示例代码...

    梦想家-mxj8922021-05-10
  • IOSiOS中UILabel实现长按复制功能实例代码

    iOS中UILabel实现长按复制功能实例代码

    在iOS开发过程中,有时候会用到UILabel展示的内容,那么就设计到点击UILabel复制它上面展示的内容的功能,也就是Label长按复制功能,下面这篇文章主要给大...

    devilx12792021-04-02
  • IOS详解iOS中多个网络请求的同步问题总结

    详解iOS中多个网络请求的同步问题总结

    这篇文章主要介绍了详解iOS中多个网络请求的同步问题总结,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...

    liang199111302021-03-15
  • IOSiOS实现控制屏幕常亮不变暗的方法示例

    iOS实现控制屏幕常亮不变暗的方法示例

    最近在工作中遇到了要将iOS屏幕保持常亮的需求,所以下面这篇文章主要给大家介绍了关于利用iOS如何实现控制屏幕常亮不变暗的方法,文中给出了详细的...

    随风13332021-04-02
  • IOSiOS自定义UICollectionViewFlowLayout实现图片浏览效果

    iOS自定义UICollectionViewFlowLayout实现图片浏览效果

    这篇文章主要介绍了iOS自定义UICollectionViewFlowLayout实现图片浏览效果的相关资料,需要的朋友可以参考下...

    jiangamh8882021-01-11
  • IOSiOS中滑动控制屏幕亮度和系统音量(附加AVAudioPlayer基本用法和Masonry简单使用)

    iOS中滑动控制屏幕亮度和系统音量(附加AVAudioPlayer基本用法和

    这篇文章主要介绍了iOS中滑动控制屏幕亮度和系统音量(附加AVAudioPlayer基本用法和Masonry简单使用)的相关资料,需要的朋友可以参考下...

    CodingFire13652021-02-26
  • IOSiOS中MD5加密算法的介绍和使用

    iOS中MD5加密算法的介绍和使用

    MD5加密是最常用的加密方法之一,是从一段字符串中通过相应特征生成一段32位的数字字母混合码。对输入信息生成唯一的128位散列值(32个字符)。这篇文...

    LYSNote5432021-02-04
  • IOSiOS开发之视图切换

    iOS开发之视图切换

    在iOS开发中视图的切换是很频繁的,独立的视图应用在实际开发过程中并不常见,除非你的应用足够简单。在iOS开发中常用的视图切换有三种,今天我们将...

    执着丶执念5272021-01-16