Objective-C计时器NSTimer学习笔记

手机APP/开发
202
0
0
2023-09-11
标签   IOS
目录
  • NSTimer - 计时器
  • NSTimer创建计时器函数
  • NSTimer触发与销毁计时器函数
  • 常用属性
  • NSRunLoop - 运行循环
  • NSRunLoop常用属性
  • NSRunLoop常用函数

NSTimer - 计时器

NSTimer派生自NSObject,是一种计时器,在经过一定的时间间隔后触发,向目标对象发送指定的消息。

计时器(NSTimer)与运行循环(RunLoop)一起工作。运行循环维护对其计时器的强引用,因此在将计时器添加到运行循环后,不必自己维护对计时器的强引用。

计时器不是实时机制。如果计时器的触发时间发生在长运行循环调用期间,或者当运行循环处于不监视计时器的模式时,计时器在下次运行循环检查计时器之前不会触发,因此计时器触发的实际时间可能要晚得多。

NSTimer创建计时器函数

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

函数描述 :使用指定的调用对象初始化计时器对象。必须使用addTimer:forMode:方法将初始化的计时器添加到运行循环中(如果计时器配置为重复,则一次计时结束无需将计时器重新添加到运行循环中)。然后,在ti过去之后,计时器将触发,由调用对象执行其调用。

参数 :

ti :计时器触发之间的秒数。如果ti小于或等于0.0,此方法将选择非负值0.1毫秒。

invocation :计时器触发时要使用的调用对象。计时器指示调用对象维护对其参数的强引用。

repeats :是否重复,如果是YES,计时器将重复重新安排自己,直到失效。如果NO,计时器将在其触发后失效。

返回值 :一个新的根据指定的参数进行配置的NSTimer对象。

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

函数描述 :使用指定的对象和选择器初始化计时器对象。必须使用addTimer:forMode:方法将新计时器添加到运行循环中(如果计时器配置为重复,则一次计时结束无需将计时器重新添加到运行循环中)。然后,经过ti秒后,计时器启动,向目标发送selector消息。

参数 :

ti :计时器触发之间的秒数。如果ti小于或等于0.0,此方法将选择非负值0.1毫秒。

aTarget :当计时器触发时,选择器指定要向其发送消息的对象。计时器维持对目标的强引用,直到它(计时器)失效。

aSelector :计时器触发时要发送给目标的消息。

repeats :是否重复,如果是YES,计时器将重复重新安排自己,直到失效。如果NO,计时器将在其触发后失效。

返回值 :一个新的根据指定的参数进行配置的NSTimer对象。

+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (NS_SWIFT_SENDABLE ^)(NSTimer *timer))block API_AVAILABLE(macosx(.12), ios(10.0), watchos(3.0), tvos(10.0));

函数描述 :使用指定的时间间隔和块初始化计时器对象。必须使用addTimer:forMode:将新计时器添加到运行循环中(如果计时器配置为重复,则一次计时结束无需将计时器重新添加到运行循环中)。然后,在间隔秒后,计时器启动,执行块。

参数 :

interval :计时器启动之间的秒数。如果间隔小于或等于0.0,此方法将选择非负值0.1毫秒。

repeats :是否重复,如果是YES,计时器将重复重新安排自己,直到失效。如果NO,计时器将在其触发后失效。

block :计时器启动时要执行的块。该块采用单个NSTimer参数,并且没有返回值。

返回值 :一个新的根据指定的参数进行配置的NSTimer对象。

- (instancetype)initWithFireDate:(NSDate *)date interval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (NS_SWIFT_SENDABLE ^)(NSTimer *timer))block API_AVAILABLE(macosx(.12), ios(10.0), watchos(3.0), tvos(10.0));

函数描述 :使用指定日期与时间间隔以及一个块初始化计时器对象。 必须使用addTimer:forMode:方法将新计时器添加到运行循环中(如果计时器配置为重复,则一次计时结束无需将计时器重新添加到运行循环中)。在指定日期到达后计时器触发,之后每间隔interval秒,计时器触发,执行block。

参数 :

date :计时器应首次启动的时间。

interval :计时器启动之间的秒数。如果间隔小于或等于0.0,此方法将选择非负值0.1毫秒。

repeats :是否重复,如果是YES,计时器将重复重新安排自己,直到失效。如果NO,计时器将在其触发后失效。

block :计时器启动时要执行的块。该块采用单个NSTimer参数,并且没有返回值。

返回值 :一个新的根据指定的参数进行配置的NSTimer对象。

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

函数描述 :使用指定的对象和选择器初始化计时器。必须使用addTimer:forMode:方法将新计时器添加到运行循环中(如果计时器配置为重复,则一次计时结束无需将计时器重新添加到运行循环中)。在指定日期到达后计时器触发,之后每间隔interval秒,计时器触发,向目标发送aSelector消息。

参数 :

date :计时器应首次启动的时间。

ti :计时器启动之间的秒数。如果间隔小于或等于0.0,此方法将选择非负值0.1毫秒。

t :当计时器触发时,选择器指定要向其发送消息的对象。计时器维持对目标的强引用,直到它(计时器)失效。

s :计时器触发时要发送给目标的消息。

ui : 计时器的用户信息。计时器维持对这个对象的强引用,直到它(计时器)失效。这个参数可以是nil。

rep : 是否重复,如果是YES,计时器将重复重新安排自己,直到失效。如果NO,计时器将在其触发后失效。

例如:需要添加到运行循环中的计时器\color{red}{例如:需要添加到运行循环中的计时器}例如:需要添加到运行循环中的计时器

- (void)viewDidLoad {
    [super viewDidLoad];
    //获取方法签名对象
    NSMethodSignature *signature = [self methodSignatureForSelector:NSSelectorFromString(@"timerAction")];
    //获取调用对象,设置调用对象调用者与调用消息
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
    invocation.target = self;
    invocation.selector = NSSelectorFromString(@"timerAction");
    //计时器加入运行循环
    [[NSRunLoop mainRunLoop] addTimer:[NSTimer timerWithTimeInterval:.0 invocation:invocation repeats:YES] forMode:NSRunLoopCommonModes];
}
///计时器调用函数
- (void)timerAction {
    NSLog(@"计时器工作中");
}

不加入运行循环,则只会打印一次,加入运行循环后,打印如下 :

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

函数描述 :创建计时器并以默认模式在当前运行循环上调度它。在ti秒过去后,计时器触发,由调用对象执行其调用。

参数 :

ti :计时器启动之间的秒数。如果ti小于或等于0.0,此方法将选择非负值0.1毫秒。

invocation :计时器触发时要使用的调用对象。计时器指示调用对象维护对其参数的强引用。

repeats :是否重复,如果是YES,计时器将重复重新安排自己,直到失效。如果NO,计时器将在其触发后失效。

返回值 : 根据指定参数配置的新NSTimer对象。

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

函数描述 :创建计时器并以默认模式在当前运行循环上调度它。在ti秒过去后,计时器触发,发送消息选择器到目标。

参数 :

ti :计时器启动之间的秒数。如果ti小于或等于0.0,此方法将选择非负值0.1毫秒。

aTarget :当计时器触发时,选择器指定要向其发送消息的对象。计时器维持对目标的强引用,直到它(计时器)失效。

aSelector :计时器触发时要发送给目标的消息。

userInfo : 计时器的用户信息。计时器维持对这个对象的强引用,直到它(计时器)失效。这个参数可以是nil。

repeats : 是否重复,如果是YES,计时器将重复重新安排自己,直到失效。如果NO,计时器将在其触发后失效。

返回值 : 根据指定参数配置的新NSTimer对象。

+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (NS_SWIFT_SENDABLE ^)(NSTimer *timer))block API_AVAILABLE(macosx(.12), ios(10.0), watchos(3.0), tvos(10.0));

函数描述 :创建一个计时器,并在默认模式下在当前运行循环中对其进行调度。在间隔秒后,计时器启动,执行块。

参数 :

interval : 计时器启动之间的秒数。如果间隔小于或等于0.0,此方法将选择非负值0.1毫秒。

repeats :是否重复,如果是YES,计时器将重复重新安排自己,直到失效。如果NO,计时器将在其触发后失效。

block :计时器启动时要执行的块。该块采用单个NSTimer参数,并且没有返回值。

返回值 :一个新的根据指定的参数进行配置的NSTimer对象。

例如:以默认模式在当前运行循环上执行计时器\color{red}{例如:以默认模式在当前运行循环上执行计时器 }例如:以默认模式在当前运行循环上执行计时器

- (void)viewDidLoad {
    [super viewDidLoad];
    [NSTimer scheduledTimerWithTimeInterval:.0 target:self selector:@selector(timerAction) userInfo:nil repeats:YES];
}
///计时器调用函数
- (void)timerAction {
    NSLog(@"计时器工作中");
}

打印如下 :

NSTimer触发与销毁计时器函数

- (void)fire;

函数描述:使计时器的消息被发送到它的目标。可以使用此方法来触发重复计时器而不中断其常规触发计划。如果计时器是非重复的,它在触发后会自动失效,即使它的预定触发日期还没有到达。

- (void)invalidate;

函数描述:停止触发的计时器,并请求将其从运行循环中删除。这个方法是从NSRunLoop对象中删除计时器的唯一方法。NSRunLoop对象会在invalidate方法返回之前或之后的某个时间点删除它对计时器的强引用。如果配置了target和userInfo对象,计时器也会删除对这些对象的强引用。

常用属性

@property (copy) NSDate *fireDate;

属性描述:计时器触发的日期。如果计时器已经失效,则为计时器触发的最后日期。可以设置此属性以调整重复计时器(repeats为YES)的触发时间。尽管重置计时器的下一次触发时间是一个相对昂贵的操作,但在某些情况下它可能更有效。例如,可以在未来想要以不规则的时间间隔多次重复某个操作的情况下使用它。调整单个计时器的触发时间比创建多个计时器对象,在一个运行循环中调度每个对象,然后销毁它们所产生的开销要小。

对于已经失效的计时器(包括已经触发的非重复计时器),不应该更改其触发日期。可以更改尚未触发的非重复计时器的触发日期,但应该始终从计时器所连接的线程进行更改。使用valid属性可以验证计时器是否有效。

@property (readonly) NSTimeInterval timeInterval;

属性描述:计时器的时间间隔,以秒为单位。如果计时器不重复,即使设置了时间间隔,也会返回0。

@property NSTimeInterval tolerance API_AVAILABLE(macos(.9), ios(7.0), watchos(2.0), tvos(9.0));

属性描述:计时器到达预定触发日期,触发时可以应用的额外时间容差。默认值为0,这意味着没有应用额外的容差。为计时器设置容差可以使其在预定触发日期到达后,偏移计时器触发。计时器可以在预定触发日期与额外时间容差加上预定触发日期之间的任何时间触发。允许系统在计时器触发时具有灵活性,可以提高系统优化的能力,以提高功耗节省和响应能力。

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

属性描述:一个布尔值,用于指示计时器当前是否有效。如果计时器仍然能够触发,则为YES;如果计时器已经失效并且不再能够触发,那么为NO。

@property (nullable, readonly, retain) id userInfo;

属性描述:计时器的userInfo对象。计时器无效后,不要访问此属性。使用valid属性验证计时器是否有效。

NSRunLoop - 运行循环

一个管理输入源(手势、Selector等)的对象,Runloop即运行循环,是iOS中的消息处理机制,其主要作用是控制NSRunLoop里面线程的执行和休眠,当某个事件执行完成后,不退出其线程而进入休眠状态,当再次检测到事件时。唤醒休眠的线程继续处理事件。RunLoop可以保持程序的持续运行,并节省CPU资源,提高程序性能。

NSRunLoop是对CFRunLoopRef的一层封装, 是Objective-C的语法的框架。CFRunLoopRef是基于C语言的开源框架。

从NSRunLoop的角度来看,NSTimer对象并不是输入源,它们是一种特殊的类型,当它们被触发时,不会导致运行循环返回。

NSRunLoop类通常不是线程安全的,只能在当前线程的上下文中调用它的方法。

NSRunLoop 处理事件流程:

NSRunLoop常用属性

@property (class, readonly, strong) NSRunLoop *currentRunLoop

属性描述:类属性,返回当前线程的运行循环(NSRunLoop对象)。如果线程还不存在运行循环,则会创建并返回一个运行循环。

@property (class, readonly, strong) NSRunLoop *mainRunLoop API_AVAILABLE(macos(.5), ios(2.0), watchos(2.0), tvos(9.0));

属性描述:类属性,返回主线程的运行循环(NSRunLoop对象)。

@property (nullable, readonly, copy) NSRunLoopMode currentMode;

属性描述:调用方的当前输入模式。这个方法仅在调用方运行时返回当前的输入模式,否则它返回nil。

Runloop模式:

1.NSDefaultRunLoopMode:默认状态(空闲状态),比如点击按钮都是这个状态

2.UITrackingRunLoopMode:滑动时的Mode。比如滑动UIScrollView时。

3.UIInitializationRunLoopMode:私有的,APP启动时。就是从iphone桌面点击APP的图标进入APP到第一个界面展示之前,在第一个界面显示出来后,UIInitializationRunLoopMode就被切换成了NSDefaultRunLoopMode。

4.NSRunLoopCommonModes:它是NSDefaultRunLoopMode和UITrackingRunLoopMode的集合。结构类似于一个数组。在这个mode下执行其实就是两个mode都能执行而已。

NSRunLoop常用函数

- (CFRunLoopRef)getCFRunLoop CF_RETURNS_NOT_RETAINED;

函数描述:返回调用方的基础CFRunLoop对象。可以使用返回的运行循环来使用Core Foundation函数调用配置当前运行循环。例如可以使用此函数来设置运行循环观察者。

返回值 :调用方的基础CFRunLoop对象。

- (void)addTimer:(NSTimer *)timer forMode:(NSRunLoopMode)mode;

函数描述:使用给定的输入模式注册给定的计时器。可以将计时器添加到多种输入模式中。在指定模式下运行时,调用方会使计时器在其计划的启动日期当天或之后启动。触发后,计时器调用其关联的处理程序例程,该例程是指定对象上的选择器。调用方保留计时器。要从安装计时器的所有运行循环模式中删除计时器,需要向计时器发送invalidate消息。

参数 :

timer :要向调用方注册的计时器。

mode :添加计时器的模式。