RunLoop(运行循环)-001-初探

RunLoop :运行循环(保证程序不退出!)(Event Loop)

Run Loop是一让线程能随时处理事件但不退出的机制。RunLoop 实际上是一个对象,这个对象管理其需要处理的 事件和消息,并提供一个入口函数来执行Event Loop 的逻辑。线程执行这个函数后,就会一直处于“接受消息->等待->处理” 的循环中,直到这个循环结束(比如传入 quit 的消息),函数返回。让线程在没有处理消息 时休眠以避免资源占用、在有消息到来时立刻被唤醒

作用

1.保住当前线程的生命!!。使程序一直运行接受用户输入

2.负责监听事件:iOS所有事件 触摸,时钟,网络等等!事件处理循环,用来不停的监听和处理输入事件并将其分配到对应的目标上进行处理

3.要想保住一条线程的生命,让这条线程有执行不完的任务(死循环)!如果没有事件发送,会让程序进入休眠状态

4.调用解耦、节省CPU时间
NSRunLoop 和 CFRunLoopRef。CFRunLoopRef 是在 CoreFoundation 框架内的,它提供了纯 C 函数的 API,所有这些 API 都是线程安全的。NSRunLoop 是基于 CFRunLoopRef 的封装, 提供了面向对象的 API,但是这些 API 不是线程安全的。
 
什么时候使用run loop
仅当在为你的程序创建辅助线程的时候,你才需要显式运行一个run loop。例如
IOS程序中UIApplication的run方法作为程序启动步骤的一部分,它在程序正常启动的时候就会启动程序的主循环。
对于辅助线程,你需要判断一个run loop是否是必须的。如果是必须的,那么你要自己配置并启动它。你不需要在任 何情况下都去启动一个线程的run loop。比如,你使用线程来处理一个预先定义的长时间运行的任务时,你应该避免 启动run loop。Run loop在你要和线程有更多的交互时才需要,比如以下情况:
 
1>.使用端口或自定义输入源来和其他线程通信
2>使用线程的定时器
3>Cocoa中使用任何performSelector...的方法
4>使线程周期性工作
关注点
Cocoa中的NSRunLoop类并不是线程安全的
我们不能再一个线程中去操作另外一个线程的run loop对象,那很可能会造成意想不到的后果。不过幸运的是 CoreFundation中的不透明类CFRunLoopRef是线程安全的,而且两种类型的run loop完全可以混合使用。Cocoa中的 NSRunLoop类可以通过实例方法:
‐(CFRunLoopRef)getCFRunLoop; 

获取对应的CFRunLoopRef类,来达到线程安全的目的。

Run loop的管理并不完全是自动的。
我们仍必须设计线程代码以在适当的时候启动run loop并正确响应输入事件,当然前提是线程中需要用到run loop。而

且,我们还需要使用while/for语句来驱动run loop能够循环运行,下面的代码就成功驱动了一个run loop:

 BOOLisRunning=NO;
 do{
 isRunning=[[NSRunLoopcurrentRunLoop]runMode:NSDefaultRunLoopModebeforeDate:[ 4 }while(isRunning);

Run loop同时也负责autorelease pool的创建和释放。

001-时钟事件

 NSTimer * timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timeMethod) userInfo:nil repeats:YES];

    //timer 添加到RunLoop运行循环中

    //NSDefaultRunLoopMode    默认模式!!

    //UITrackingRunLoopMode   UI模式!!

    //NSRunLoopCommonModes    占位模式!! UI&&默认! UI和默认都可以进行,互不影响

    //UI模式优先级最高!!  UI模式只会被触摸事件所触发!!

//    [[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];

//    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];

    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

002-RunLoop启动和停止(退出)

@property(nonatomic,assign) BOOL finished;

    _finished = NO;

    HKThread * thread = [[HKThread alloc] initWithBlock:^{

        NSTimer * timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timeMethod) userInfo:nil repeats:YES];

        [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];

        //[[NSRunLoop currentRunLoop] run];//就是一个死循环!! 无法停止UIApplicationMain也是死循环

        NSLog(@"come here");

        while (!self->_finished) {

            [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.0001]];

        }

    }];

    [thread start];//点击屏幕 线程被干掉

 

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event

{

    _finished = YES;

}

 

    HKThread * thread = [[HKThread alloc] initWithBlock:^{

        NSLog(@"%@-----",[NSThread currentThread]);

        while (true) {

            [[NSRunLoop currentRunLoop] run];

        }

    }];

    [thread start];

    

     [self performSelector:@selector(otherMethod) onThread:thread withObject:nil waitUntilDone:NO];

    -(void)otherMethod{

       NSLog(@"OtherMethod --- %@",[NSThread currentThread]);

    }

003-RunLoop source讲解

 Source : 事件源(输入源) 按照函数调用栈,Source分类

 Source0:非Source1 就是 例如用户点击事件

 Source1:系统内核事件或者其他线程间的通信

@property(nonatomic,strong)dispatch_source_t timer;//调度源 用于自动提交事件处理程序块、调度队列以响应外部事件

 //队列

    dispatch_queue_t queue = dispatch_get_global_queue(0,0);

    

    //创建一个定时器!!

    self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);

    

    //设置定时器

    dispatch_source_set_timer(self.timer, DISPATCH_TIME_NOW, 1000000000, 0);//纳秒为单位 1000000000 为 1秒

    dispatch_source_set_event_handler(self.timer, ^{

        NSLog(@"-------%@",[NSThread currentThread]);

    });

    

    //启动定时器

     dispatch_resume(self.timer);

 

原文地址:https://www.cnblogs.com/StevenHuSir/p/RunLoop_Brief.html