RunLoop

作者: weyan | 来源:发表于2018-11-26 08:30 被阅读0次

1、 Runloop

RunLoop RunLoop RunLoop RunLoop RunLoop对象 RunLoop资料 运行结构(RunLoop处理逻辑-官方版) RunLoop处理逻辑

2、RunLoop与线程

RunLoop与线程
#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    //OC语言的API
    //01 获得主线程对应的runloop对象 主运行循环
    NSRunLoop *mainRunloop = [NSRunLoop mainRunLoop];
    //NSLog(@"%@",mainRunloop);
    
    //02 获得当前的runloop对象
    NSRunLoop *currentRunloop = [NSRunLoop currentRunLoop];
//    NSLog(@"%p---%p",currentRunloop,mainRunloop);
    
    
    //C语言的API
    //01 主运行循环
    CFRunLoopRef mainRunloopRef = CFRunLoopGetMain();
    //02 当前的运行循环
    CFRunLoopRef currentRunloopRef = CFRunLoopGetCurrent();
    NSLog(@"%p-%p",mainRunloopRef,currentRunloopRef);
    
    //转换
    NSLog(@"%p-%p",mainRunloop.getCFRunLoop,mainRunloopRef);
    
    [NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];
}

-(void)run{
    NSLog(@"run---%@",[NSThread currentThread]);
    //子线程调用
    //NSLog(@"%@",[NSRunLoop currentRunLoop]);
    
    //runloop和线程的关系
    //(1) 一一的对应的关系(字典)
    //(2) 主线程对应的runloop默认已经创建并且开启了,而子线程对应的runloop需要手动创建并开启
    //(3) 线程销毁,那么runloop也将销毁
    
    //获得子线程对应的runloop |currentRunLoop该方法本身是懒加载的,如果是第一调用那么会创建当前线程对应的runloop并保存,以后调用则直接获取
    NSRunLoop *newThreadRunloop = [NSRunLoop currentRunLoop];
    NSLog(@"%@",newThreadRunloop);
    
    [newThreadRunloop run]; //开启runloop (该runloop开启后马上退出了)
}

@end

3、RunLoop相关类

RunLoop相关类 RunLoop运行模式 RunLoop运行模式 几种运行模式
----------------------RunLoop运行模式和Timer------------------------
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [self performSelectorInBackground:@selector(timer2) withObject:nil];
}

-(void)timer1
{
    //01 创建定时器对象
    NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];
    
    //02 添加到runloop中
    //Mode :runloop的运行模式(5-默认|界面跟踪|占位)
    //把定时器对象添加到runloop中,并指定运行模式为默认:(只有当运行模式为NSDefaultRunLoopMode的时候,定时器才会工作)
    //[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
    
    //当滚动textView的时候,主运行循环会切换运行模式(默认->界面追踪运行模式)
    //把定时器对象添加到runloop中,并指定运行模式为界面跟踪:(只有当运行模式为NUITrackingRunLoopMode的时候,定时器才会工作)
    //[[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];
    
    //要求不管有没有在滚动控件,定时器都能够正常工作
    //[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
    //[[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];
    
    //把定时器对象添加到runloop中,并指定运行模式为commonModes:
    //只有当运行模式为被标记为commonModes的运行模式的时候,定时器才会工作
    //被标记为commonModes运行模式:UITrackingRunLoopMode | kCFRunLoopDefaultMode
    /*
    common modes = <CFBasicHash 0x7fa4c9d00d70 [0x10a3f17b0]>{type = mutable set, count = 2,
        entries =>
        0 : <CFString 0x10b2ed270 [0x10a3f17b0]>{contents = "UITrackingRunLoopMode"}
        2 : <CFString 0x10a411b60 [0x10a3f17b0]>{contents = "kCFRunLoopDefaultMode"}
    }*/
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
}

-(void)timer2
{
    NSLog(@"timer++++++%@",[NSThread currentThread]);
    
    //定时器工作
    //该方法内部会自动将创建的定时器对象添加到当前的runloop,并且指定运行模式为默认
    NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];
    
    //为了保证滑动textView时,定时器继续工作,需要知道运行模式为占位模式
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

    //手动创建子线程对应的runloop
    [[NSRunLoop currentRunLoop] run];
}

-(void)run
{
    NSLog(@"run----%@",[NSRunLoop currentRunLoop].currentMode);
}

4、GCD中的定时器

#import "ViewController.h"

@interface ViewController ()

@property (nonatomic, strong) dispatch_source_t timer;


@end

@implementation ViewController

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    //NSTimer中的定时器工作会受到runloop运行模式的影响
    //GCD中的定时器是精准的,不受影响
    
    //01 创建定时器对象
    /* 参数说明
     *
     * 第一个参数:source的类型 DISPATCH_SOURCE_TYPE_TIMER 定时器leixing
     * 第二个参数:对第一个参数的描述
     * 第三个参数:更详细的描述
     * 第四个参数:队列(GCD-4) 决定代码块(event_handler)在哪个线程中执行(串行队列-主线程|并发主队列-子线程)
     */
    dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0, 0));
    
    //02 设置定时器(开始时间|调用间隔|精准度)
    /* 参数说明
     *
     * 第一个参数:定时器对象
     * 第二个参数:开始计时的时间  DISPATCH_TIME_NOW 现在开始
     * 第三个参数:间隔时间
     * 第四个参数:精准度(允许的误差)
     */
    dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 2.0 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
    
    //03 事件回调(定时器执行的任务)
    dispatch_source_set_event_handler(timer, ^{
        NSLog(@"GCD---%@",[NSThread currentThread]);
    });
    
    //04 启动定时器
    dispatch_resume(timer);
    
    //05 添加一个引用
    self.timer = timer;
}
@end

5、CFRunLoopSourceRef

CFRunLoopSourceRef就是inputSource 函数调用栈

总结:

RunLoop总结

注意:
1、有线程不一定有RunLoop,但有RunLoop就必须有线程
2、线程销毁或者给runloop设定的时间到的话runloop就会退出

6、CFRunLoopObserverRef

CFRunLoopObserverRef
-------------------------RunLoopObserverRef的使用------------------------
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    /**01 创建观察者对象
    *参数说明:
    *allocator 分配存储空间(默认)
    *activities 需要监听runloop的状态
    *repeats 是否持续监听 yes
    *order   0
    */
    /**CFRunLoopObserverRef ob = CFRunLoopObserverCreateWithHandler(CFAllocatorRef allocator, CFOptionFlags activities, Boolean repeats, CFIndex order, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
     
    })
    */
    CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {

        /*运行状态:
         kCFRunLoopEntry = (1UL << 0),
         kCFRunLoopBeforeTimers = (1UL << 1),
         kCFRunLoopBeforeSources = (1UL << 2),
         kCFRunLoopBeforeWaiting = (1UL << 5),
         kCFRunLoopAfterWaiting = (1UL << 6),
         kCFRunLoopExit = (1UL << 7),
         kCFRunLoopAllActivities = 0x0FFFFFFFU
         */
        switch (activity) {
            case kCFRunLoopEntry:
                NSLog(@"runloop即将进入");
                break;
            case kCFRunLoopBeforeTimers:
                NSLog(@"即将处理timer事件");
                break;
            case kCFRunLoopBeforeSources:
                NSLog(@"即将处理source事件");
                break;
            case kCFRunLoopBeforeWaiting:
                NSLog(@"即将进入休眠");
                break;
            case kCFRunLoopAfterWaiting:
                NSLog(@"被唤醒");
                break;
            case kCFRunLoopExit:
                NSLog(@"runloop退出");
                break;

            default:
                break;
        }
    });

  /*02 监听当前runloop的运行状态
   *参数说明
   *
   *第一参数:runloop对象
   *第二参数:监听者
   *第三参数:监听runloop在哪种运行模式下的状态
   */
    CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);

    [NSTimer scheduledTimerWithTimeInterval:4.0 target:self selector:@selector(timerRun) userInfo:nil repeats:YES];
}

-(void)timerRun
{
    NSLog(@"处理收到的事件--timer--RUN");
}

7、代码模拟RunLoop死循环

#import <Foundation/Foundation.h>

void msg(int n){
    NSLog(@"runloop被唤醒");
    NSLog(@"runloop处理%d这个任务",n);
}

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSLog(@"runloop启动啦");
        do {
            NSLog(@"runloop即将处理timer事件");
             NSLog(@"runloop即将处理source事件");
             NSLog(@"还有事件响应我来处理吗?");
             NSLog(@"runloop进入到休眠");
            int number = 0;
            scanf("%d",&number);
            msg(number);
        } while (1);
    }
    return 0;
}

8、RunLoop的应用

runloop应用
  • 应用01
应用01
  • 应用02
应用02

9、关于RunLoop内部的自动释放池

关于RunLoop内部的自动释放池

相关文章

网友评论

      本文标题:RunLoop

      本文链接:https://www.haomeiwen.com/subject/kkxpnftx.html