iOS 如何使用 NSTimer 以及 runloop 和 NSTimer 的关系
来源:互联网 发布:java权限系统思路 编辑:程序博客网 时间:2024/04/25 17:23
这几天在研究 RunLoop,记录一下runloop 和 NSTimer 的关系,毕竟这个使我们比较常用的.
关于 runloop 参考资料很多, 我看的是 ibireme (郭耀源)的博客,国内开源大牛,程序员的楷模,他的博客链接
在 ios 系统中,每启动一个线程,都会跟一个对应的 runloop,runloop 默认是关闭的 需要我们手动获取,设置并启动,(详细参考上面的博客),主线程例外,系统自动为主线程启动一个 runloop 并配置完毕.这里我们不管,主要看unloop 和 NSTimer 的关系, 如何正确使用 NSTimer.
NSTimer 的创建方法
NSTimer *time1 = [NSTimer alloc]initWithFireDate:<#(nonnull NSDate *)#> interval:<#(NSTimeInterval)#> repeats:<#(BOOL)#> block:<#^(NSTimer * _Nonnull timer)block#>; NSTimer *timer2 = [NSTimer alloc]initWithFireDate:<#(nonnull NSDate *)#> interval:<#(NSTimeInterval)#> target:<#(nonnull id)#> selector:<#(nonnull SEL)#> userInfo:<#(nullable id)#> repeats:<#(BOOL)#>; NSTimer *timer3 = [NSTimer scheduledTimerWithTimeInterval:<#(NSTimeInterval)#> target:<#(nonnull id)#> selector:<#(nonnull SEL)#> userInfo:<#(nullable id)#> repeats:<#(BOOL)#>]; NSTimer *timer4 = [NSTimer scheduledTimerWithTimeInterval:<#(NSTimeInterval)#> invocation:<#(nonnull NSInvocation *)#> repeats:<#(BOOL)#>]; NSTimer *timer5 = [NSTimer scheduledTimerWithTimeInterval:<#(NSTimeInterval)#> repeats:<#(BOOL)#> block:<#^(NSTimer * _Nonnull timer)block#>];
首先所有的 timer 必须要加入 runloop 中才能生效.
然后使用 timer 要尤其注意释放时机,否则很容易导致内存泄露或者其他麻烦.
/* 关于 timer1 在主线程中使用, * 在没有加入 runloop 的情况下, 可以使用 fire 立即执行一次, 但是对于设置的repeat:YES 就没有效果了,block 只会执行一次 * 如果 repeat:NO 那么 timer 在执行一次之后会自动释放, [timer fire]之后,再次调用[timer fire] 就没有效果了 * 再加入 runloop 的情况下, 把 timer 加入 runloop 就会执行. 因为主线程的 runloop 一直在运行,所以我们主要获取 runloop * 在加入定时器就好. 不需要调用 [runloop run] * 加入 runloop 之后,repeat:NO时,定时器执行一次就会释放当前 VC,repeat:YES 当前 VC 被持有,必须显示执行[_timer1 invalidate] * 释放 timer1才能释放 VC, 否则妥妥的内存泄露 */ self.timer1 = [[NSTimer alloc]initWithFireDate:[NSDate dateWithTimeIntervalSinceNow:1] interval:1 repeats:NO block:^(NSTimer * _Nonnull timer) { NSLog(@"执行 timer1 程序"); }]; // [self.timer1 fire]; NSRunLoop *runloop = [NSRunLoop currentRunLoop]; [runloop addTimer:_timer1 forMode:(NSDefaultRunLoopMode)];// [runloop run];// [_timer1 invalidate];
/* timer1 在子线程中使用 * * 使用情况和在主线程中是一样的,要注意的是 加入当前 runloop 的时候,要启动 runloop, 因为子线程的 runloop 默认是关闭的 * */ dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_async(queue, ^{ self.timer1 = [[NSTimer alloc]initWithFireDate:[NSDate dateWithTimeIntervalSinceNow:1] interval:1 repeats: YES block:^(NSTimer * _Nonnull timer) { NSLog(@"执行 timer1 程序"); }]; NSRunLoop *runloop = [NSRunLoop currentRunLoop]; [runloop addTimer:_timer1 forMode:(NSDefaultRunLoopMode)]; [runloop run];// [self.timer1 fire]; });
/* 关于 timer2 在主线程中使用, * 在没有加入 runloop 的情况下, 可以使用 fire 立即执行一次, 但是对于设置的repeat:YES 就没有效果了,timerAction 只会执行一次 *You must add the new timer to a run loop, using addTimer:forMode:. Upon firing, the timer sends the message aSelector to target. (If the timer is configured to repeat, there is no need to subsequently re-add the timer to the run loop.) *但是官方推荐使用这个方法我们必须要加入 runloop ,其实正常使用确实是要你加入 runloop 的 * 参数 repeat: If YES, the timer will repeatedly reschedule itself until invalidated. If NO, the timer will be invalidated after it fires. * 如果 repeat:NO 那么 timer 在执行一次之后会自动释放, [timer fire]之后,再次调用[timer fire] 就没有效果了 * 参数 userInfo: Custom user info for the timer. The timer maintains a strong reference to this object until it (the timer) is invalidated. This parameter may be nil. * 该方法允许 timer 携带一个参数 userInfo(字典),里面可以包含我们想要携带的参数,可以为 nil,但是要注意的是 这个定时器对当前对应也是强持有 * 再加入 runloop 的情况下, 把 timer 加入 runloop 就会执行. 因为主线程的 runloop 一直在运行,所以我们主要获取 runloop * 在加入定时器就好. 不需要调用 [runloop run] * 加入 runloop 之后,repeat:NO时,定时器执行一次就会释放当前 VC,repeat:YES 当前 VC 被持有,必须显示执行[_timer1 invalidate] * 释放 timer1才能释放 VC, 否则妥妥的内存泄露 * 子线程使用 注意事项是一样的 参考一下timer1就知道了 */ self.timer2 = [[NSTimer alloc]initWithFireDate:[NSDate dateWithTimeIntervalSinceNow:1] interval:1 target:self selector:@selector(timerAction:) userInfo:nil repeats:YES]; //self.timer2.userInfo// [self.timer2 fire]; NSRunLoop *runloop = [NSRunLoop currentRunLoop]; [runloop addTimer:_timer2 forMode:(NSDefaultRunLoopMode)];// [runloop run];// [_timer2 invalidate];
/* 这三种方法 根上面的区别就是 创建 timer 并且自动加到当前的 runloop 当中. 所以在主线程里可以直接运行 * 子线程中 子线程 runloo 启动就可以执行 timer * 注意事项 和 前面两个情况是一样的 repeat:YES 要注意合适的时机显示 失效 timer 否则注意内存泄露 * * 这里注意下 NSInvocation 的用法, timer4的参数 就是这个 * */ self.timer3 = [NSTimer scheduledTimerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) { NSLog(@"执行 timer3 程序"); }]; NSTimer *timer4 = [NSTimer scheduledTimerWithTimeInterval:1 invocation:nil repeats:YES]; NSTimer *timer5 = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timerAction:) userInfo:nil repeats:YES]; dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_async(queue, ^{ NSTimer *timer5 = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timerAction:) userInfo:nil repeats:YES]; // 自动加入当前的 runloop 只需要获取当前 runloop 并启动 即可 NSRunLoop *runloop = [NSRunLoop currentRunLoop]; [runloop run]; });
注意 NSInvocation 的使用
NSInvocation 用法
//NSInvocation;用来包装方法和对应的对象,它可以存储方法的名称,对应的对象,对应的参数, /* NSMethodSignature:签名:再创建NSMethodSignature的时候,必须传递一个签名对象,签名对象的作用:用于获取参数的个数和方法的返回值 */ //创建签名对象的时候不是使用NSMethodSignature这个类创建,而是方法属于谁就用谁来创建 NSMethodSignature*signature = [SSSViewController instanceMethodSignatureForSelector:@selector(sendMessageWithNumber:WithContent:)]; //1、创建NSInvocation对象 NSInvocation*invocation = [NSInvocation invocationWithMethodSignature:signature]; invocation.target = self; //invocation中的方法必须和签名中的方法一致。 invocation.selector = @selector(sendMessageWithNumber:WithContent:); /*第一个参数:需要给指定方法传递的值 第一个参数需要接收一个指针,也就是传递值的时候需要传递地址*/ //第二个参数:需要给指定方法的第几个参数传值 NSString*number = @"1111"; //注意:设置参数的索引时不能从0开始,因为0已经被self占用,1已经被_cmd占用 [invocation setArgument:&number atIndex:2]; NSString*number2 = @"啊啊啊"; [invocation setArgument:&number2 atIndex:3]; //2、调用NSInvocation对象的invoke方法 //只要调用invocation的invoke方法,就代表需要执行NSInvocation对象中制定对象的指定方法,并且传递指定的参数// [invocation invoke]; /* * After ti seconds have elapsed, the timer fires, invoking invocation. * 当 timer到了执行点的时候 会 invoking invocation. 触发 invocation.里面的方法 * 使用 invocation. 就可以执行 我们自定义的方法 ,携带多个自定义的参数 */ NSTimer *timer4 = [NSTimer scheduledTimerWithTimeInterval:1 invocation:(invocation) repeats:YES];
1 0
- iOS 如何使用 NSTimer 以及 runloop 和 NSTimer 的关系
- NSTimer和Runloop的关系
- iOS开发学习之NSTimer失效、NSTimer与runloop之间的关系、解密NSTimer
- NSTimer详解----使用、保留环问题、与runloop的关系
- ios NSTimer引起的循环引用,以及NSTimer的使用
- NStimer和Runloop之间的关系(NSTimer和其他事件同时显示执行)
- NSTimer的使用以及NSTimer暂停和继续
- IOS中NSTimer使用及runloop
- iOS中UIScrollView和UIPageControl以及NSTimer的综合使用
- (iOS开发) RunLoop与NSTimer的相关
- iOS CADisplayLink以及和NSTimer的区别
- iOS NSTimer的使用
- iOS NSTimer 的使用
- iOS NSTimer的使用
- NSTimer的两种创建方式以及跟RunLoop的简单结合使用
- IOS 定时器NSTimer的使用
- IOS-NSTimer的使用
- iOS NSTimer 定时器的使用
- 处理java网络通信粘包问题
- 在使用set/map时,一个可爱的小bug:java.util.ConcurrentModificationException
- 编写高质量OC代码52建议总结:25.总是为第三方类的分类名称加前缀
- 带您了解mysql CONCAT()函数
- Android Memory定位内存泄漏
- iOS 如何使用 NSTimer 以及 runloop 和 NSTimer 的关系
- 线程
- Javascript提交form表单
- 设计模式之访问者模式
- Rubygem报no such name xxx.gemspec.rz的解决
- Vue2.0组件之间通信
- CSS选择符
- Android studio 代码调试
- java.util.List与java.awt.List区别