iOS NSTimer和RunLoop问题
1.浅谈RunLoop
runLoop从字面的意思上看是运行中的循环,作用是保持APP的持续运行,处理APP的各种事件,比如点击事件、定时器事件、Selector事件,节省CPU资源,提高APP的性能,能够让线程在有工作的时候忙碌,在没有工作的时候休眠
2.RunLoop和线程的关系
1.runLoop和线程是紧密关联的,可以说是为了线程而生,没有线程,runLoop也没存在的必要。
2.runLoop和线程是一一对应的,主线程的runLoop默认是创建的,子线程的需要手动创建。currentRunLoop懒加载的,在同一个子线程中创建多个runloop,则返回的都是同一个对象,因为其是懒加载模式的
获得主线程的runLoop:NSRunLoop *mainRunLoop =[NSRunLoop mainRunLoop];
获得当前线程runLoop:NSRunLoop *currentRunLoop =[NSRunLoop currentRunLoop];
3.在runloop中有多个运行模式,但是runloop只能选择一种模式运行,mode里面至少要有一个timer或者是source
4.在第一次获取时创建,在线程结束时销毁
3.RunLoop的几个类
1.CFRunLoopRef:NSRunLoop对象是OC对象,是对CFRunLoopRef的封装,可以通过getCFRunLoop方法获取其对应的CFRunLoopRef对象。注意,NSRunLoop不是线程安全的,但CFRunLoopRef是线程安全的
2.RunLoopMode:NSRunLoop对象是一系列RunLoopMode的集合,每个mode包括有这个模式下所有的Source源、Timer源和观察者。每次RunLoop调用的时候都只能调用其中的一个mode,接收这个mode下的源,通知这个mode下的观察者。这样设计的主要目的就是为了隔离各个模式下的源和观察者,使其不相互影响,常用的五种模式:
kCFRunLoopDefaultMode:App默认的mode,一般情况下App都是运行在这个mode 下的
UITrackingRunLoopMode:界面跟踪时的mode,一般用于ScrollView滚动的时候追 踪的,保证滑动的时候不受其他事件影响
UIInitializationRunLoopMode:在刚启动 App 时第进入的第一个 Mode,启动完成后就不再使用
GSEventReceiveRunLoopMode:接受系统事件的内部 Mode,一般用不到
kCFRunLoopCommonModes:占位mode,可以向其中添加其他mode用以检测多个mode的事件
3.CFRunLoopSourceRef:事件源产生的地方
4.CFRunLoopTimerRef:是基于事件的触发器,其中包含一段时间长度、延期容忍度和一个函数指针(回调方法)。当其加入到RunLoop中时,RunLoop会注册一个时间点,当到达这个时间点后,会触发对应的事件。
5.CFRunLoopObserverRef:RunLoop的观察者。每个观察者都可以观察RunLoop在某个模式下事件的触发并处理
kCFRunLoopEntry:即将进入runLoop
kCFRunLoopBeforeTimers:即将处理Timer
kCFRunLoopBeforeSources:即将处理Source
kCFRunLoopBeforeWaiting:即将进入休眠
kCFRunLoopAfterWaiting:刚从休眠中被唤醒
kCFRunLoopExit:即将退出RunLoop
4.NSTimer在RunLoop中的使用
图1方式一:
图2方式二:
5.RunLoop常驻线程
注意事项:当进入block的时候,先创建了timer,并且也把timer也把timer加入到runloop中,但是很重要的一点子线程中Runloop不会自动运行,需要手动运行,因为这里没有运行Runloop,所以timer就被释放掉了,所以导致了啥都没有。
小知识:[[NSRunLoop currentRunLoop] run],运行runloop,
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];指定runloop在指定模式下,设置开始时间,开启成功会返回YES
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate distantFuture]];
运行runloop直到一个时间