软件测试之SDK开发(ios)——谈谈RunLoop

最近在开发SDK的时候,用到了多线程技术,为了观察线程的状态,就要使用RunLoop。

计算机处理任务有进程和线程的概念,而在iOS中一个App只能开启一个进程,但是线程可以开启多个。一般来讲,一个线程一次只能执行一个任务,执行完成后线程就会退出。
当我们需要一个常驻线程,可以让线程在需要做事的时候忙起来,不需要的话就让线程休眠,可以这样做:

do {
   //获取消息
   //处理消息
} while (消息 != 退出)

上面的这种循环模型被称作 Event Loop。 IOS中的RunLoop就是这种循环模型。

1、 RunLoop的作用

  • 1、使程序一直运行并接受用户输入
    程序一启动就会开一个主线程,主线程一开起来就会跑一个主线程对应的RunLoop,RunLoop保证主线程不会被销毁,也就保证了程序的持续运行。
  • 2、决定程序在何时应该处理哪些Event
    比如:触摸事件,定时器事件,Selector事件等
  • 3、节省CPU时间
    程序运行起来时,什么操作都没有做的时候,RunLoop就告诉CPU,现在没有事情做,我要去休息,这时CPU就会将其资源释放出来去做其他的事情,当有事情做的时候RunLoop就会立马起来去做事情

2、线程与RunLoop的关系

线程和 RunLoop 之间是一一对应的;其关系保存在一个全局的 Dictionary 里,线程作为key,RunLoop作为value;线程创建之后是没有RunLoop的(主线程除外);RunLoop在第一次获取时创建,在线程结束时销毁。RunLoop可以通过[NSRunLoop currentRunLoop]或者CFRunLoopGetCurrent()来获取。

3、RunLoop内部逻辑

在这里插入图片描述

  • 1、 通知观察者 RunLoop 启动,之后调用内部函数,进入Loop,下面的流程都在Loop内部do-while函数中执行。
  • 2、通知观察者: RunLoop 即将触发 Timer 回调。(kCFRunLoopBeforeTimers)
  • 3、通知观察者: RunLoop 即将触发 Source0 回调
    (kCFRunLoopBeforeSources)
  • 4、RunLoop 触发 Source0 回调。
  • 5、如果有 Source1 处于等待状态,直接处理这个 Source1 然后跳转到第9步处理消息。
  • 6、通知观察者:RunLoop 的线程即将进入休眠(sleep)。(kCFRunLoopBeforeWaiting)
  • 7、调用 mach_msg监听唤醒端口,系统内核将这个线程挂起,停留在mach_msg_trap状态,等待接受 mach_port 的消息。线程将进入休眠, 直到被某一个事件唤醒
  • 8、通知观察者线程已经被唤醒
    (kCFRunLoopAfterWaiting)
  • 9、处理事件
  • 10、系统通知观察者: RunLoop 即将退出

将观察者添加到线程的runloop中,如下代码所示

- (void)addSourceToRunloop
{
    CFRunLoopSourceContext context = {0,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
    _source = CFRunLoopSourceCreate(NULL, 0, &context);
    CFRunLoopAddSource([_runloop getCFRunLoop], _source, kCFRunLoopCommonModes);
    _observer = CFRunLoopObserverCreateWithHandler(kCFAllocatorDefault , kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
        if (activity == kCFRunLoopBeforeTimers || activity == kCFRunLoopBeforeSources || activity == kCFRunLoopBeforeWaiting) {
            
    });
    CFRunLoopAddObserver([_runloop getCFRunLoop], _observer, kCFRunLoopCommonModes);
    CFRelease(_source);
}

将观察者移除线程的runloop中,如下代码所示

-(void)stop
{
    if ([NSThread currentThread] == self) {
        if (_source) {
            CFRunLoopRemoveObserver(CFRunLoopGetCurrent(), _observer, kCFRunLoopCommonModes);
            CFRelease(_observer);
            CFRunLoopSourceInvalidate(_source);
            CFRunLoopRemoveSource(CFRunLoopGetCurrent(), _source, kCFRunLoopCommonModes);
            CFRelease(_source);
            _source = nil;
            CFRunLoopStop(CFRunLoopGetCurrent());
        }
    }
    else
    {
        [self syncWork:^{
            [self stop];
        }];
    }
}

参考文章

1、https://juejin.im/post/5c9e28ddf265da307261efff
2、https://juejin.im/post/5cacb2baf265da03904bf93b
3、https://www.jianshu.com/p/86705c95c224

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值