iOS中定时器NSTimer的一些用法总结

转载 2015年07月06日 22:20:01

NSTimer在IOS开发中会经常用到,尤其是小型游戏,然而对于初学者时常会注意不到其中的内存释放问题,将其基本用法总结如下:

一、初始化方法:有五种初始化方法,分别是

+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo;

?
1
2
3
4
5
6
7
8
9
10
11
12
- (void)viewDidLoad {
    [super viewDidLoad];
    //初始化一个Invocation对象
    NSInvocation * invo = [NSInvocation invocationWithMethodSignature:[[self class] instanceMethodSignatureForSelector:@selector(init)]];
    [invo setTarget:self];
    [invo setSelector:@selector(myLog)];
    NSTimer * timer = [NSTimer timerWithTimeInterval:1 invocation:invo repeats:YES];
    //加入主循环池中
    [[NSRunLoop mainRunLoop]addTimer:timer forMode:NSDefaultRunLoopMode];
    //开始循环
    [timer fire];
}

+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo;

?
1
  NSTimer * timer = [NSTimer scheduledTimerWithTimeInterval:1 invocation:invo repeats:YES];

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

?
1
NSTimer * timer = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(myLog) userInfo:nil repeats:NO]

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

?
1
NSTimer * timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(myLog:) userInfo:@"123" repeats:YES]

- (instancetype)initWithFireDate:(NSDate *)date interval:(NSTimeInterval)ti target:(id)t selector:(SEL)s userInfo:(id)ui repeats:(BOOL)rep 

?
1
2
 NSTimer * timer = [[NSTimer alloc]initWithFireDate:[NSDate distantPast] interval:1 target:self selector:@selector(myLog:) userInfo:nil repeats:YES];
    [[NSRunLoop mainRunLoop]addTimer:timer forMode:NSDefaultRunLoopMode];

注意:这五种初始化方法的异同:

        1、参数repeats是指定是否循环执行,YES将循环,NO将只执行一次。

        2、timerWithTimeInterval这两个类方法创建出来的对象如果不用 addTimer: forMode方法手动加入主循环池中,将不会循环执行。并且如果不手动调用fair,则定时器不会启动。

        3、scheduledTimerWithTimeInterval这两个方法不需要手动调用fair,会自动执行,并且自动加入主循环池。

        4、init方法需要手动加入循环池,它会在设定的启动时间启动。

二、成员变量

@property (copy) NSDate *fireDate;

这是设置定时器的启动时间,常用来管理定时器的启动与停止

?
1
2
3
4
    //启动定时器
    timer.fireDate = [NSDate distantPast];
    //停止定时器
    timer.fireDate = [NSDate distantFuture];

@property (readonly) NSTimeInterval timeInterval;

这个是一个只读属性,获取定时器调用间隔时间。

@property NSTimeInterval tolerance;

这是7.0之后新增的一个属性,因为NSTimer并不完全精准,通过这个值设置误差范围。

@property (readonly, getter=isValid) BOOL valid;

获取定时器是否有效

@property (readonly, retain) id userInfo;

获取参数信息

三、关于内存释放

如果我们启动了一个定时器,在某个界面释放前,将这个定时器停止,甚至置为nil,都不能是这个界面释放,原因是系统的循环池中还保有这个对象。所以我们需要这样做:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
-(void)dealloc{
    NSLog(@"dealloc:%@",[self class]);
}
- (void)viewDidLoad {
    [super viewDidLoad];
    timer= [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(myLog:) userInfo:nil repeats:YES];
    UIButton *btn = [[UIButton alloc]initWithFrame:CGRectMake(0, 0, 100, 100)];
    btn.backgroundColor=[UIColor redColor];
    [btn addTarget:self action:@selector(btn) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:btn];
}
-(void)btn{
    if (timer.isValid) {
        [timer invalidate];
    }
    timer=nil;
    [self dismissViewControllerAnimated:YES completion:nil];
}

在官方文档中我们可以看到 [timer invalidate]是唯一的方法将定时器从循环池中移除。



OS程序进入后台后十分钟之内就会被系统kill掉,怎么解决呢?我想要程序进入后台后仍然运行计时功能,否则就无法达到考试的目的,之后在网上查阅了相关资料最后终于找到答案,其精髓就是:利用苹果给出的三种类型的程序可以保持在后台运行:音频播放类,位置更新类,另外一个记不太清楚了,我利用了苹果给出的音频播放类的这个“特权”来满足我程序上的要求,详细步骤如下:

1、步骤一:在Info.plist中,添加"Required background modes"键,value为:App plays audio

步骤二:

复制代码
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
    // Override point for customization after application launch.
    NSError *setCategoryErr = nil;
    NSError *activationErr  = nil;
    [[AVAudioSession sharedInstance]
     setCategory: AVAudioSessionCategoryPlayback
     error: &setCategoryErr];
    [[AVAudioSession sharedInstance]
     setActive: YES
     error: &activationErr];
    self.window.backgroundColor = [UIColor whiteColor];
    [self.window makeKeyAndVisible];
    return YES;
}
复制代码

步骤三:将以下代码添加到appDelegate文件中的- (void)applicationDidEnterBackground:(UIApplication *)application函数,也可添加到在具体类中注册的应用进入后台后的通知方法

复制代码
- (void)applicationDidEnterBackground:(UIApplication *)application{

    UIApplication*   app = [UIApplication sharedApplication];
    __block    UIBackgroundTaskIdentifier bgTask;
    bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
        dispatch_async(dispatch_get_main_queue(), ^{
            if (bgTask != UIBackgroundTaskInvalid)
            {
                bgTask = UIBackgroundTaskInvalid;
            }
        });
    }];
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        dispatch_async(dispatch_get_main_queue(), ^{
            if (bgTask != UIBackgroundTaskInvalid)
            {
                bgTask = UIBackgroundTaskInvalid;
            }
        });
    });

}

问题解决之后遇到的一个新问题,我的页面上有一个UIScrollView和一个定时器用来记录当前考试模式下的剩余时间,问题出现了:当我滑动滚动试图时,定时器的方法便不在运行(即被UI主线程阻塞)。google一下找到了解决办法:将定时器放在非主线程中执行将更新UI的操作放到主线程,这样UI主线程和定时器就能互不干扰的相互工作了,以下是主要代码:

复制代码
  1 #import "CountdownTool.h"
  2 
  3 @interface CountdownTool()
  4 {
  5     UILabel *_lblShow;
  6     NSTimer *_timer;
  7 }
  8 @property (nonatomic, assign) NSInteger hour;
  9 @property (nonatomic, assign) NSInteger minute;
 10 @property (nonatomic, assign) NSInteger second;
 11 @property (nonatomic, copy) NSString  *strHour;
 12 @property (nonatomic, copy) NSString  *strMinute;
 13 @property (nonatomic, copy) NSString  *strSecond;
 14 @property (nonatomic, assign) NSInteger totalSeconds;
 15 @end
 16 @implementation CountdownTool
 17 @synthesize hour = _hour;
 18 @synthesize minute = _minute;
 19 @synthesize second = _second;
 20 @synthesize totalSeconds = _totalSeconds;
 21 
 22 - (void)dealloc
 23 {
 24     [_lblShow release];
 25     [_strHour release];
 26     [_strMinute release];
 27     [_strSecond release];
 28     [super dealloc];
 29 }
 30 
 31 - (id)initWithFrame:(CGRect)frame
 32 {
 33     self = [super initWithFrame:frame];
 34     if (self) {
 35         _lblShow = [[UILabel alloc] initWithFrame:self.bounds];
 36         _lblShow.backgroundColor = [UIColor clearColor];
 37         _lblShow.font = [UIFont systemFontOfSize:15];
 38         _lblShow.textColor = [UIColor yellowColor];
 39         _lblShow.textAlignment = NSTextAlignmentCenter;
 40         _lblShow.numberOfLines = 1;
 41         [self addSubview:_lblShow];
 42     }
 43     return self;
 44 }
 45 
 46 - (id)initWithFrame:(CGRect)frame andMinutesNum:(NSInteger)minute
 47 {
 48     if (self = [self initWithFrame:frame]) {
 49         self.totalSeconds = minute * 60;
 50         //多线程启动定时器
 51        [NSThread detachNewThreadSelector:@selector(startTimer) toTarget:self withObject:nil];
 52     }
 53     return self;
 54 }
 55 - (void)startTimer
 56 {
 57     _timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(timerFire) userInfo:nil repeats:YES];
 58     [[NSRunLoop currentRunLoop] run];
 59 }
 60 - (void)handleWithTotalSeconds
 61 {
 62     self.hour = _totalSeconds/3600;
 63     self.minute = _totalSeconds%3600/60;
 64     self.second = _totalSeconds%3600%60;
 65     if (_hour <= 0) {
 66         _lblShow.text = [NSString stringWithFormat:@"%@:%@",_strMinute,_strSecond];
 67     }else{
 68         _lblShow.text = [NSString stringWithFormat:@"%@:%@:%@",_strHour,_strMinute,_strSecond];
 69     }
 70 }
 71 - (void)setHour:(NSInteger)hour
 72 {
 73     _hour = hour;
 74     if (_hour < 10) {
 75         self.strHour = [NSString stringWithFormat:@"0%d",_hour];
 76     }else{
 77         self.strHour = [NSString stringWithFormat:@"%d",_hour];
 78     }
 79 }
 80 - (void)setMinute:(NSInteger)minute
 81 {
 82     _minute = minute;
 83     if (_minute < 10) {
 84         self.strMinute = [NSString stringWithFormat:@"0%d",_minute];
 85     }else{
 86         self.strMinute = [NSString stringWithFormat:@"%d",_minute];
 87     }
 88 }
 89 - (void)setSecond:(NSInteger)second
 90 {
 91     _second = second;
 92     if (_second < 10) {
 93         self.strSecond = [NSString stringWithFormat:@"0%d",_second];
 94     }else{
 95         self.strSecond = [NSString stringWithFormat:@"%d",_second];
 96     }
 97 }
 98 - (void)setTotalSeconds:(NSInteger)totalSeconds
 99 {
100     _totalSeconds = totalSeconds;
101     [self performSelectorOnMainThread:@selector(handleWithTotalSeconds) withObject:nil waitUntilDone:YES];
102 }
103 - (void)timerFire
104 {
105     if (_totalSeconds == 0) {
106         [_timer invalidate];
107         return;
108     }
109     self.totalSeconds -= 1;
110 }
111 @end


相关文章推荐

ios学习7_iPhone屏幕尺寸、分辨率及适配

1.iPhone尺寸规格 设备 iPhone 宽 Width 高 Height 对角线 Diagonal ...

Window定时器得用法

Windows定时器可以看作是一个信号发生器,当用户设定得时间耗尽时,系统会自动调用定时器得回调函数。windows API设定一个定时器得函数为Settimer,函数原型如下:UINT_PTR Se...

IOS NSTimer 定时器用法总结

IOS NSTimer 定时器用法总结

iOS - 中三种定时器的用法NSTimer、CADisplayLink、GCD

一、NSTimer 1.创建方法 NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:sel...

iOS 中三种定时器的用法NSTimer、CADisplayLink、GCD

标签:ios   定时器   nstimer   cadisplaylink   gcd    一、NSTimer 1.创建方...

iOS中定时器NSTimer的使用

调用一次计时器方法: //不重复,只调用一次。timer运行一次就会自动停止运行 NSTimer * timer = [NSTimer scheduledTimerWithTimeInterva...

IOS中定时器NSTimer的开启与关闭

调用一次计时器方法: myTimer = [NSTimer scheduledTimerWithTimeInterval:1.5 target:self selector:@selector(s...
  • enuola
  • enuola
  • 2012-10-22 16:58
  • 150200

iOS中定时器NSTimer的使用

1、初始化 + (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelec...

ios-NSRunLoop以及定时器NSTimer-理解

http://www.cnblogs.com/liyang31tg/p/3662557.html?utm_source=tuicool [NSTimer scheduledTimerWithTi...

IOS中定时器NSTimer的开启与关闭

调用一次计时器方法: [cpp] view plaincopy myTimer = [NSTimer scheduledTimerWithTimeI...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)