ios 知识点总结(十一)之RUNLOOP

####1.iOS系统中,提供了两种Runloop:NSrunloop和CFRunLoopRef;

  • CGRunLoopRe是在CoreFoundation框架内的,提供纯C函数的API,所有的API都是线程安全的。
  • NSRunloop是基于CFRunloopref的封装,提供了面向对象的API,但是这些API不是线程安全的。

###2.使用场景

  • 不开启runloop:在处理耗时的操作时,一般都会开辟一个子线程,操作完成之后,子线程线性的执行代码然后退出,此时是不开启runloop的。
  • 开启runloop:
    1)当创建一个全局线程时,当开始之后,并子线程线性执行完成之后就处于死亡状态,不能再重新开启。
    2)Event Loop模式:线程的任务直到我们主动让线程退出为止永远不会结束,可以在需要的时候让线程做对应的事情。
    3)RunLoop能正常运行的条件:至少要包含一个Mode,并且该Mode下需要至少一个事件源(Timer/Source),而且要运行在有事件源的mode下,但是经过NSRunLoop封装之后,只可以往mode中添加两类事件:NSPort和NSTimer。
    4)RunLoop是寄生于线程的纤细循环机制,它能保证线程存活,而不是线性执行完任务就消亡。
    5)Runloop与线程是一一对应的,每个线程只有唯一与之对应的一个Runloop,只能在当前线程中获取线程对应的RunLoop,但是主线程除外。
    6)子线程默认没有RunLoop,需要我们去主动开启。
    7)RunLoop有三种启动方式run、runUntilDate:(NSDate *)limitDate、runMode:(NSString *)mode beforeDate:(NSDate *)limitDate。第一种无条件永远运行RunLoop并且无法停止,线程永远存在。第二种会在时间到后退出RunLoop,同样无法主动停止RunLoop。前两种都是在NSDefaultRunLoopMode模式下运行。第三种可以选定运行模式,并且在时间到后或者触发了非Timer的事件后退出。
  • 让线程定时执行任务
    NSTimer并不是严格的按照设定的时间点来触发的,一般会会在runloop循环一次时执行(但还是会根据当前任务执行的时间长短来决定50-100ms),但是NSTimer提供了一个toerance属性来设置宽容忍度,可以是NSTimer尽可能的答道精准。
  • scrollView滑动对NStimer的影响
    偶尔我们会发现,NStimer在我们滑动ScrolleView的时候,NStimer会停止不起作用,这是因为:
    1)在runloop起作用时,runloop每次只能执行在一个mode下,主要是让不同的mode中的Item互不影响。
    2)Nstimer默认是在NSDefaultRunLoopMode中,一般其情况下主线程就是在NSDefaultRunLoopMode下,所有NSTimer可以正常运行。
    3)但是当滑动ScroolView时,主线程的runloop自动切换到了UITrackingRunLoopMode,所以现在的runloop需要处理该mode下的item,但是NStimer并不在该Mode下,runloop就不会处理NStimer了。
    4)当ScrollerView滑动结束之后,Runloop自动切换到NSDefaultRunLoopMode,这时NSTimer就又正常运行了。
    5)所以如果想让NStimer正常运行,我们需要把Item(timer/source)同时加入多个Mode(NSRunLoopCommonModes),这样不管runloop处于什么mode下,item都是当前Mode的item,都会得到处理。
  • NStimer导致Viewcontroller无法释放
    原因:为了确保Nstimer正常运转,当Nstimer加入到Runloop以后系统会对NStimer执行一次retain,一般情况下我们设置NSTimer时都会设置Target为Self,这时Nstimer会对Controller有一个强引用,这时会导致两者互相持有而无法释放。
    解决方法:
    1)把NStimer封装到另一个Target中,控制器通过这个target间接使用NStimer。
    2)另一种方式时直接增加NSTimer的扩展(分类),让NSTImer自身作为Target,同时可以将操作封装在Block中,例如:NSTimer+Block
    3)所以一般在使用Timer时需要与invaildate成对出现,不管时重复执行还是在单次执行都要在结束时执行incaildate,只是在单次执行完成之后会自动调用invaildate方法。
  • Runloop释放的问题
    1.在主线程中
    1)当runloop开启时,会自动创建一个自动缓存池。
    2)当Runloop在休息之前会释放掉自动缓存池的东西。
    3)然后重新创建一个信的空的自动缓存池
    4)当Runloop被唤醒又开始重新跑圈时,Timer,source等新时间就会放到新的自动缓存池中,后面就重复2-4的操作。
    2.Nsthread和NSOperationQueue开辟子线程需要手动创建autoreasepool,GCD开辟子线程不需要手动创建,因为GCD的每个队列都会自动创建autoreleasepool。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章