iOS RunloopDemo解析

Runloop

Runloop是一个底层的机制, 运行循环

Runloop作用

  1. 保证当前线程不退出, 运行程序的入口为main, 比如说我们main函数中

    1
    2
    3
    4
    5
    NSLog(@"okle%@",[NSThread currentThread]);
    //在UIApplicationMain有一个死循环,开启了当前线程的Runloop循环
    int ceshi = UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    NSLog(@"啦啦啦");
    return ceshi;

    运行后第一个输出为 “ okle “ 并且当前线程为主线程, 第二个啦啦啦是不会输出的, 因为在UIApplicationMain中开启了当前线程了Runloop循环

  2. 监听用户的输入, 触摸事件, 时钟事件, 网络事件( 本质上就是电信号转化为二进制数据,拿到数据操作系统知道,然后反馈给应用程序 )

  3. 每一条线程上面都有一个Runloop, 默认关闭, 主线程默认开启

    Timer解析

    时钟事件

    方案一

    默认模式, 苹果建议时钟事件和网络事件

    1
    [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerMethod) userInfo:nil repeats:YES];

方案二 ( MODE )

当我们写为以下代码, 单纯的运行时没有问题的, Time也是可以开启

1
2
3
NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timerMethod) userInfo:nil repeats:true];
//加入Runloop中
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];

但是当我们添加了触摸事件, 触摸屏幕时, 此时Timer就关闭了, 当我们将MODE切换到UI模式, 但是此时只能在触摸屏幕时触发Timer, 下图是我简单画的一个示例图

将我们的Timer放在UI模式下,但是UI模式只能被触摸事件所唤醒下面我们简单来写一个例子
UI模式优先级最高,Runloop优先处理UI模式,UI模式只能被触摸事件唤醒
当我们将MODE模式切换为NSRunLoopCommonModes占位模式时此就就可以搞定了
除此之外系统内核模式/初始化模式

方案三( NSRunLoopCommonModes ) 弊端

  1. 如果操作中有耗时操作

    1
    2
    3
    4
    5
    - (void)timerMethod{
    [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:1.0]];//睡一秒钟
    static int a = 0;
    NSLog(@"%d--%@",a++,[NSThread currentThread]);
    }
  2. 解析模拟与验证
    此时运行UI就卡了, 那么我们考虑耗时操作应该放在子线程, 如下代码

    1
    2
    3
    4
    5
    6
    7
    8
    //开辟子线程
    NSThread * thread= [[NSThread alloc]initWithBlock:^{
    //加入Runloop中
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
    NSLog(@"okle%@",[NSThread currentThread]);
    }];
    [thread start];

    但是并没有走回调? 此时我们来创建一个MBXBNSThread类, 并且实现MBXBNSThread中的dealloc方法

    1
    2
    3
    - (void)dealloc{
    NSLog(@"完蛋了吗老铁?");
    }

    此时再次运行, 发现我们现走了线程已经over了, 输出如下RunloopDemo_MBXB[10241:7007519] 完蛋了吗老铁? 走不到回调了, 此时再次用strong来修饰一下, 然而对象还在, 线程是有cpu来管理的, 虽然没有打印但是还是配有打印回调, 因为当我们的线程执行完一条任务之后线程就挂掉了, 此时我们加一句代码来测试

    1
    2
    3
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    [_thread start];
    }

    此时猜想会出现什么问题, 一个已经释挂掉的线程, 当然系统会提示我们开启一个新线程, 如何保持线程不会被挂掉

  3. 保持线程不挂掉
    测试:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    MBXBNSThread *thread = [[MBXBNSThread alloc]initWithBlock:^{
    //加入Runloop中
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
    NSLog(@"okle%@",[NSThread currentThread]);
    //此时此处加一个死循环
    while(true){
    }
    }];

    此时我们加入了一个死循环, 线程确实不会挂掉了, 当然我们又想到去监听, 写不下去了
    当然苹果给我提供了方法Runloop

  4. 开启当前线程的Runloop循环

    1
    2
    3
    4
    5
    6
    7
    MBXBNSThread *thread = [[MBXBNSThread alloc]initWithBlock:^{
    //加入Runloop中
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
    NSLog(@"okle%@",[NSThread currentThread]);
    // 开启Runloop
    [[NSRunLoop currentRunLoop] run];
    }];

    此时就解决了

  5. GCDtimer

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    //#define NSEC_PER_SEC 1000000000ull
    //#define NSEC_PER_MSEC 1000000ull
    //#define USEC_PER_SEC 1000000ull
    //#define NSEC_PER_USEC 1000ull
    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, 1.0*NSEC_PER_SEC, 0);
    dispatch_source_set_event_handler(self.timer, ^{
    NSLog(@"%@",[NSThread currentThread]);
    });
    dispatch_resume(self.timer);

    此时我们增加触摸事件后并没有以上情况一样发生那样的情况

Source

CFRunLoopSourceRef 事件源 ( 输入源 )
按照函数调用栈, Source分为两类
Source0 : 非系统内核事件
Source1 : 系统内核事件

好了, 给大家这个简单demo, 当然在代码中也写了注释, 可以去我的git下载, 欢迎star
下载链接 : demo地址

技术交流q群150731459

吃粑粑的毕教授 wechat
欢迎您扫一扫上面的微信公众号,订阅文章!

本文标题:iOS RunloopDemo解析

文章作者:吃粑粑的毕教授

发布时间:2017年12月02日 - 12:12

最后更新:2017年12月02日 - 14:12

原始链接:http://www.2bjs.com/架构/iOS Runloop/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

给糖吃的人都是最美丽最帅气的人,感谢你们哦
0%