首页编程nstimeinterval 如何判断nstimer正在调用

nstimeinterval 如何判断nstimer正在调用

编程之家2023-11-03118次浏览

无论是nstimeinterval还是如何判断nstimer正在调用,它们都是当前热门话题。如果你对它们感到好奇,那么请跟随小编的脚步,一起来揭开它们的秘密吧!

nstimeinterval 如何判断nstimer正在调用

ios cadisplaylink和timer的区别

一、NSTimer

1.创建方法

NSTimer*timer= [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(action:) userInfo:nil repeats:NO];

TimerInterval:执行之前等待的时间。比如设置成1.0,就代表1秒后执行方法

target:需要执行方法的对象。

selector:需要执行的方法

nstimeinterval 如何判断nstimer正在调用

repeats:是否需要循环

2.释放方法

[timer invalidate];

注意:调用创建方法后,target对象的计数器会加1,直到执行完毕,自动减1。如果是循环执行的话,就必须手动关闭,否则可以不执行释放方法。

3.特点

存在延迟:不管是一次性的还是周期性的timer的实际触发事件的时间,都会与所加入的RunLoop和RunLoop Mode有关,如果此RunLoop正在执行一个连续性的运算,timer就会被延时出发。重复性的timer遇到这种情况,如果延迟超过了一个周期,则会在延时结束后立刻执行,并按照之前指定的周期继续执行。

nstimeinterval 如何判断nstimer正在调用

必须加入Runloop:使用上面的创建方式,会自动把timer加入MainRunloop的NSDefaultRunLoopMode中。如果使用以下方式创建定时器,就必须手动加入Runloop:

NSTimer*timer= [NSTimer timerWithTimeInterval:5 target:self selector:@selector(timerAction) userInfo:nil repeats:YES];

[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];

二、CADisplayLink

1.创建方法

displayLink= [CADisplayLink displayLinkWithTarget:self selector:@selector(handleDisplayLink:)];

[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

2.停止方法

[displayLink invalidate];

displayLink= nil;

当把CADisplayLink对象add到runloop中后,selector就能被周期性调用,类似于重复的NSTimer被启动了;执行invalidate操作时,CADisplayLink对象就会从runloop中移除,selector调用也随即停止,类似于NSTimer的invalidate方法。**

3.特点:

屏幕刷新时调用:CADisplayLink是一个能让我们以和屏幕刷新率同步的频率将特定的内容画到屏幕上的定时器类。CADisplayLink以特定模式注册到runloop后,每当屏幕显示内容刷新结束的时候,runloop就会向CADisplayLink指定的target发送一次指定的selector消息, CADisplayLink类对应的selector就会被调用一次。所以通常情况下,按照iOS设备屏幕的刷新率60次/秒

延迟:iOS设备的屏幕刷新频率是固定的,CADisplayLink在正常情况下会在每次刷新结束都被调用,精确度相当高。但如果调用的方法比较耗时,超过了屏幕刷新周期,就会导致跳过若干次回调调用机会。

如果CPU过于繁忙,无法保证屏幕60次/秒的刷新率,就会导致跳过若干次调用回调方法的机会,跳过次数取决CPU的忙碌程度。

使用场景:从原理上可以看出,CADisplayLink适合做界面的不停重绘,比如视频播放的时候需要不停地获取下一帧用于界面渲染。

4.重要属性

frameInterval

NSInteger类型的值,用来设置间隔多少帧调用一次selector方法,默认值是1,即每帧都调用一次。

duration

readOnly的CFTimeInterval值,表示两次屏幕刷新之间的时间间隔。需要注意的是,该属性在target的selector被首次调用以后才会被赋值。selector的调用间隔时间计算方式是:调用间隔时间= duration× frameInterval。

三、GCD

1.执行一次

double delayInSeconds= 2.0;

dispatch_time_t popTime= dispatch_time(DISPATCH_TIME_NOW, delayInSeconds* NSEC_PER_SEC);

dispatch_after(popTime, dispatch_get_main_queue(), ^(void){

//执行事件

});

2.重复执行

NSTimeInterval period= 1.0;//设置时间间隔

dispatch_queue_t queue= dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_source_t _timer= dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);

dispatch_source_set_timer(_timer, dispatch_walltime(NULL, 0), period* NSEC_PER_SEC, 0);//每秒执行

dispatch_source_set_event_handler(_timer, ^{

//在这里执行事件

});

dispatch_resume(_timer);

如何判断nstimer正在调用

scheduledTimerWithTimeInterval:(NSTimeInterval)seconds

预订一个Timer,设置一个时间间隔。

表示输入一个时间间隔对象,以秒为单位,一个>0的浮点类型的值,如果该值<0,系统会默认为0.1

target:(id)aTarget

表示发送的对象,如self

selector:(SEL)aSelector

方法选择器,在时间间隔内,选择调用一个实例方法

userInfo:(id)userInfo

此参数可以为nil,当定时器失效时,由你指定的对象保留和释放该定时器。

repeats:(BOOL)yesOrNo

当YES时,定时器会不断循环直至失效或被释放,当NO时,定时器会循环发送一次就失效。

invocation:(NSInvocation*)invocation

iOS 属性 @property

声明@property时,注意关键词及字符间的空格。

@property的本质其实是: ivar(实例变量)+ getter+ setter;

接下来逐个介绍一下,每个关键词的作用:

指定获取属性对象的名字为 getterName,如果你没有使用 getter指定 getterName,系统默认直接使用 propertyName访问即可。通常来说,只有所指属性需要我们指定 isPropertyName对应的 Bool值时,才使用指定 getterName,一般直接用 PropertyName即可。 setter=setterName:则是用来指定设置属性所使用的的 setter方法,即设置属性值时使用 setterName:方法,此处 setterName是一个方法名,因此要以":"结尾,具体示例如下:

表示强引用关系,即修饰对象的引用计数会+1,通常用来修饰对象类型,可变集合及可变字符串类型。当对象引用计数为0,即不被任何对象持有,且此对象不再显示在列表中时,对象就会从内存中释放。

对象不进行 retain操作,即不改变对象引用计数。通常用来修饰基本数据类型( NSInteger, CGFloat, Bool, NSTimeInterval等),内存在栈上由系统自动回收。

assign也可以用来修饰 NSObject类型对象,因为 assign不会改变修饰对象的引用计数,所以当修饰对象的引用计数为0,对象销毁的时候,对象指针不会被自动清空。而此时对象指针指向的地址已被销毁,这时再访问该属性会产生野指针错误: EXC_BAD_ACCESS,因此 assign通常用来修饰基本数据类型。

当调用修饰对象的 setter方法时,会建立一个引用计数为 1的新对象,即对象会在内存里拷贝一份副本,两个指针指向不同的内存地址。一般用于修饰字符串( NSString)和集合类( NSArray, NSDictionary)的不可变变量, Block也是用 copy修饰。

针对 copy,这里又牵涉到了深 copy和浅 copy的问题,这里做一下简单介绍,后续会有文章专门探讨这个问题:

注意:当使用 copy修饰的属性赋值时, copy出来的是一份不可变对象。因此当对象是一个可变对象时,切记不要使用 copy进行修饰。如果这时使用 copy修饰,当使用 copy出来的对象调用可变对象所特有的方法时,会因为找不到对应的方法而 Crash。

表示弱引用关系,修饰对象的引用计数不会增加,当修饰对象被销毁的时候,对象指针会自动置为 nil,防止出现野指针。 weak也用来修饰 delegate,避免循环引用。另外 weak只能用来修饰对象类型,且是在 ARC下新引入的修饰词, MRC下相当于使用 assign。

weak的底层实现是基于 Runtime底层维护的 SideTables的 hash数组,里面存储的是一个 SideTable的数据结构:

这里重点说一下 weak_entry_t定长数组到动态数组的切换,首先会将原来定长数组中的内容转移到动态数组中,然后再在动态数组中插入新的元素。

而对于动态数组中元素个数大于或等于总空间的 3/4时,会对动态数组进行总空间* 2的扩容

每次动态数组扩容,都会将原先数组中的内容重新插入到新的数组中。

备注:此处省略了 weak底层实现的很多细节,具体详细实现,后续会单独发文介绍。

设置属性函数 reallySetProperty(...)的原子性非原子性实现如下:

获取属性函数 objc_getProperty(...)的内部实现如下:

由此可见,对属性对象的加锁操作仅限于对象的 getter/setter操作,如果是 getter/setter以外的操作,该加锁并没有意义。因此 atomic的原子性,仅能保障对象的 getter/setter的线程安全,并不能保障多线程下对对象的其他操作安全。如一个线程在 getter/setter操作,另一个线程进行 release操作,可能会导致 crash。此种场景的线程安全,还需要由开发者自己进行处理。

那如何给 Category实现类似实例变量功能呢?简单列举两种方式,此处暂时不做具体详解,后续会有文章单独介绍:

根据苹果官方文档的建议,如果捕获的引用永远不会变为 nil,我们应该使用 unowned,否则应该使用 weak。

@property延展相关的技术点有很多,如: copy相关的 NSCopying协议, weak底层详细的实现原理,如何保障对象的多线程安全。还有很多技术点跟 Runtime、Runloop有关,后续文章会陆续介绍。

知识点完整说下来就是一整套系统的协同运转,各个环节紧密相扣,最终才成为我们现在看到的样子。本文及以后的文章都会尽可能的收缩一下单篇文章探讨的范围,以期能够让话题更加紧密。

好了,本文到此结束,如果可以帮助到大家,还望关注本站哦!

开发网站网络公司 网站建设公司哪家比较好html5动画制作 用html5制作的动画片有哪些