RunLoop

Event驱动  主体就是一个死循环,没事-休眠,有事-唤醒-执行  

runloop:用于解决类似你滑动了屏幕产生了多个事件,为了解耦不影响用户操作,将这些事件加入一个消息队列,这边就不用再去管理这些事件,不会影响操作也不会影响事件的执行,它会从队列中取出一个一个的执行。主线程不需要等待事件处理完成才能进行下一步操作。

1、使程序一直运行并接受用户输入

2、决定程序在何时应该处理哪些Event

3、调用解耦(Message Queue)

4、节省cpu时间,runLoop会造成类似的死循环,使CPU一直在运行,但是它可以休眠在没事的时候不会让cpu运行的机制。

NSTimer依赖与runloop实现。

UIEvent从产生到分发都是通过runloop跑的。

Autorelease与runloop有关

CAdisplayLink 是每画一贞60ps或者30ps就回调一次。

CATransition 动画效果,push等改变frame等等的效果

CAAnimation UIView的动画效果

NSURLConnection AFNetworking delegate和网络回来的数据都是通过runloop跑的

断点时 会看到调用堆栈 (如 Thread1)堆栈里面的很多东西都是有runloop搞出来的,看的时候从底下往上看。大部分堆栈都会看到start到runloop 上面的调用可能不一样。

 

主线程或者含有runloop的线程都从一下六个之一的函数调起:

source0:处理App内部事件,app自己负责管理(触发),如UIEvent,CFSocket

source1:由runloop和内核管理,Mach port驱动,如CFMachPort(NSPort是对它的封装)、CFMessagePort

runloop构成元素:

 

UIkit通过RunLoopObserver在Runloop两次sleep对AutoreleasePool进行pop和push将这次Loop 中产生的Autorelease对象释放。

RunLoop在同一时间只能且必须在一种特定的Mode下Run

更换Mode时,需要停止当前loop,然后重启loop。

Mode是iOS app滑动门顺畅的关键

 

CFRunLoopMode:

NSDefaultRunLoopMode 默认状态,空闲状态,程序起来切换到这个mode,不滑动就一直是这个mode

UITrackingRunLoopMode 滑动scrollView时的Mode

UIInitializationRunLoopMode 私有 app启动时的Mode

NSRunLoopCommonModes(结构类似数组)mode集合

NSTimer:不管是重复性的timer还是一次性的timer都会对它的方法的接收者进行retain,这两种timer的区别在于“一次性的timer在完成调用以后会自动将自己invalidate,而重复的timer则将永生,直到你显示的invalidate它为止”。 

               timer对它的接收者进行retain,从而保证了timer调用时的正确性,但是又引入了接收者的内存管理问题。特别是对于重复性的timer,它所引用的对象将一直存在,将会造成内存泄露。

    对于重复的timer一定要在特定的时候调用invalidate使它失效,因为repeats为YES时会对它的接受者(self)造成强引用而无法释放造成内存泄漏。必须在viewWillDisappear的时候,将计数器timer停止,否则可能会导致内存泄露。    

  1. //取消定时器  之后一定要将定时器置为空,否则还是没有释放。
  2. [timer invalidate];  
  3. timer = nil;  

要想实现:先停止,然后再某种情况下再次开启运行timer,可以使用下面的方法:

  1. //关闭定时器  
  2. [myTimer setFireDate:[NSDate distantFuture]]; 

  

  1. //开启定时器  
  2. [myTimer setFireDate:[NSDate distantPast]];
  3. 使用场景:界面消失的时候关闭定时器,显示的时候打开定时器。

NSTimer为什么要添加到RunLoop中才会有作用

  前面的例子中我们使用的是一种便利方法,它其实是做了两件事:首先创建一个timer,然后将该timer添加到当前runloop的default mode中。也就是这个便利方法给我们造成了只要创建了timer就可以生效的错觉,我们当然可以自己创建timer,然后手动的把它添加到指定runloop的指定mode中去。NSTimer也是一种sourece,所有的source如果要起作用,就地加入到runloop中去,如果一个runloop没有包含任何资源,runloop会立马退出。

  timer 默认添加的是defalut mode 这种mode不负责处理滑动事件,所以滑动的时候是不会执行timer的。

  若是不希望timer收到scrollView的影响,需要自己创建定时器,然后添加到NSRunLoopCommonModes中。滑动的时候被切换到UITrackingRunLoopMode中,不是默认的mode,所以timer不执行。

  

 

NSTimer加到了runloop中但是不触发事件:

1、runloop是否运行。每一个线程都有自己的runloop,程序主线程会自动使runloop生效,但是对于我们自己新建的线程的runloop是不会自动运行的,需要我们自己启动runloop运行。

2、mode是否正确

  想要timer生效就要将它添加到runloop的指定的mode中去,通常是加入主线程的defalut mode,但是我们这样做了为什么timer还是没有触发事件这是为什么?

  这是因为timer添加的时候需要指定一个mode,因为同一线程的runloop在运行的时候只能处于一种mode。当处于timer添加的mode时候timer才能得到触发事件的机会。所以 要让timer生效,必须保证该线程的runloop已启动,而且运行的runloop的mode也要匹配。

timer在子线程中,此时线程不处于子线程,那么子线程的runloop停掉,timer也停掉。

 

runloop与dispatch_get_main_queue():gcd中dispatch到main queue的block被分发到main runloop执行。

 

RunLoop的挂起与唤醒:

  按debug的暂停键能看到一个堆栈。

 

AFNetworking中的runloop:

TableView cell延迟加载图片的新思路:

  1、UI解决方法,滑的时候不去设,停止之后去加载图片

  2、runloop 在cell里面把设图片这个事 在defalut mode里面去做,滑的时候就不会去设,不会影响滑动的帧数。

 

让Crash的App回光返照:

 

  

posted @ 2016-12-01 12:34  yiki  阅读(210)  评论(0编辑  收藏  举报