对于RunLoop的一些简单理解

一、RunLoop的作用

  众所周知OC是运行时的语言,程序是在运行的过程中去确定对象的类型,同时再去调用类和对象响应的方法,但是无论是面向对象的OC语言,又或者是面向过程的C语言,在最终执行的时候总归是面向过程的。

  就像最简单的Hello World,App在运行的开始就被激活,一直就处于潜伏监视的状态,等运行到需要执行的代码后执行相应的操作,执行完毕之后再次潜伏...我的个人理解就是主线程在App运行的时候就开始了监视,有任务就跑出来执行,任务执行完毕就潜伏监视,寻找下一个任务... 而负责管理线程何时执行任务、何时潜伏监视的机制,就是RunLoop机制

  其实我们在开发过程中一直使用着RunLoop机制,只是没有可以的去注意而已...

 

二、RunLoop与线程的关系

  RunLoop是用来管理线程的,即每一个线程都有一个RunLoop对象。可以通过具体的方法去获得。在主线程中,MainRunLoop是默认创建并运行激活的

  虽然每一个线程都可以获取 RUnLoop对象,但是并不是每一个线程中都有实例对象,也就是说如果我们不获取RunLoop,这个RunLoop的实例对象也许就不存在,而当我们获取时, 如果不存在,就会去创建。

 

三、NSRunLoop

  NSRunLoop是Cocoa框架中的类,与之对应的是在Core Fundation中有一个CFRunLoopRef类。这两者的区别是前者不是线程安全的,而CFRunLoopRef是线程安全的。

  1、获取主线程的NSRunLoop

//获取主线程的NSRunLoop
+(NSRunLoop *)mainRunLoop;

  2、获取当前线程的NSRunLoop

//获取当前线程的RunLoop:有的话就直接获取,没有的话就自动创建
+(NSRunLoop *)currentRunLoop;

  3、NSRunLoop的执行模式

//获取当前runloop的执行模式
@property(readonly,copy)NSString *currentMode;
//两种执行模式
//默认的模式,接收大部分输入源的响应
NSString *const NSDefaultRunLoopMode;
//多种模式的集合
NSString *const NSRunLoopCommonModes;

  4、获取RunLoop的CFRunLoopRef对象

//获取RunLoop的CFRunLoopRef对象
-(CFRunLoopREF)getCFRunLoop;

  5、将定时器添加到RunLoop中

//将定时器添加到runloop中
-(void)addTimer:(NSTimer *)timer forMode:(NSString *)mode;

  6、获取下个响应时间

-(NSDate *)limitDateForMode:(NSString *)mode;

  定时器的执行,其实并不是按照时间段额间隔进行调用方法,而是在定时器注册到 RunLoop中后,RunLoop会设置一个一个的时间点进行调用,例如,5,10,15,20等等。如果错过了某个时间点,定时器并不会延迟调用,而 是直接等待下一个时间点调用,所以定时器并不是准确的。

  7、在某个时间期限前接收相应

-(void)aceptInputForMode:(NSString *)mode beforeDate:(NSDate *)limitDate;

  8、开始运行

-(void)run;

  9、到某个时间点运行

-(void)runUntilDate:(NSDate *)limitDate;

  10、在某个期限前运行

-(BOOL)runMode:(NSString *)mode beforeDate:(NSDate *)limitDate;

  11、将输入源端口移除  

- (void)addPort:(NSPort *)aPort forMode:(NSString *)mode;

添加输入源端口到runloop中,NSPort对象可以理解为详细的载体,会传递消息与其代理。



- (void)removePort:(NSPort *)aPort forMode:(NSString *)mode;

将某个输入源端口移除

 

四、RunLoop的调用

  RunLoop是自动执行的,因此一般情况下我们很少去显式调用或者启动RunLoop,但是下边的两种情况需要手动设置。

  1、在分线程中使用定时器

  定时器的实现是基于RunLoop的,平时我们使用定时器或许并没有对RunLoop做什么操作,那是因为主线程的RunLoop默认是开启运行的,如果我们进行如下操作:

-(void)viewDidLoad{
  [super viewDidLoad];
  dispatch_queue_t queue = dispatch_queue_create("myQueue",DISPATCH_QUEUE_CONCURRENT);
 dispatch_async(queue,^{
    NSTimer *timer = [NSTimer scheduledTimerWithTimerInterval:1 target:self selector:@selector(time) userInfo:nil repeats:YES];
});     
}
-(void)time{
NSLog(@"runTimer");
}

  此时运行,控制台不会输出runTimer。我们必须在线程中手动的执行如下代码:

[[NSRunLoop currentRunLoop] run];

  这样定时器才可以正常工作。

 

  2、当线程中使用如下的方法时  

  某些延迟函数和选择器在分线程中的使用,我们必须手动开始RunLoop

@interface NSObject (NSDelayedPerforming)

- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay inModes:(NSArray *)modes;

- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay;

+ (void)cancelPreviousPerformRequestsWithTarget:(id)aTarget selector:(SEL)aSelector object:(id)anArgument;

+ (void)cancelPreviousPerformRequestsWithTarget:(id)aTarget;


- (void)performSelector:(SEL)aSelector target:(id)target argument:(id)arg order:(NSUInteger)order modes:(NSArray *)modes;

- (void)cancelPerformSelector:(SEL)aSelector target:(id)target argument:(id)arg;
- (void)cancelPerformSelectorsWithTarget:(id)target;

 

五、其他

  输入源被注册到RunLoop中时会有方法进行remove。但是定时器没有remove,但是它的invalidate方法可以将其从 RunLoop中移除。invalidate是重要的也是唯一的将定时器从RunLoop中注销的方法,所以如果我们创建了定时器,就一定要再不适用的时 候调用invalidate方法。

 

六、附

  该文借鉴他人文章,参考自:http://www.mamicode.com/info-detail-1023504.html

posted @ 2016-04-01 16:36  斯文小书生  阅读(633)  评论(0编辑  收藏  举报