RunLoop总结

2018-07-19  本文已影响7人  细雨菲菲v

1.什么是runloop?

RunLoop是通过内部维护的事件循环来对事件/消息进行管理的一个对象。

事件循环

main函数是为什么可以一直保证运行状态,而不退出 ?
在main函数当中,所调用的UIApplicationMain()内部会启动主线程的runloop,而runloop又是对事件循环的一种维护机制,可以做到在有事做的时候做事,没有事情做的时候,会通过从用户态到内核态的切换,从而避免资源的占用,让当前线程处于一种休眠状态。

2.数据结构

NSRunLoop是CFRunLoop的封装,提供了面向对象的API.

CFRunLoop

截图3.png
CFRunLoopMode
截图4.png
CFRunLoopSource

CFRunLoopTimer
基于事件的定时器

CFRunLoopObserver
观测时间点

各个数据结构之间的关系

截图5.png
RunLoop的Mode
截图6.png
CommonMode的特殊性

NSRunLoopCommonModes

3.事件循环的实现机制

void CFRunLoopRun()

截图7.png
截图8.png

4.NSRunLoop与NSTimer

滑动TableView的时候我们的定时器还会生效吗?

截图9.png
解决方案
void CFRunLoopAddTimer(runLoop, timer,commonMode)

5.RunLoop与多线程

线程和RunLoop一一对应的。
自己创建的线程默认是没有RunLoop的

(1)怎样实现一个常驻线程?

a.为当前线程开启一个RunLoop;
[NSRunLoop currentRunLoop]或者CFRunLoopGetCurrent()
b.向该RunLoop中添加一个Port/Source等维护RunLoop的事件循环;
c.启动该RunLoop。

#import "MCObject.h"
@implementation MCObject
static NSThread *thread = nil;
// 标记是否要继续事件循环
static BOOL runAlways = YES;
+ (NSThread *)threadForDispatch{
    if (thread == nil) {
        @synchronized(self){
            if (thread == nil) {
                //线程的创建
                thread = [[NSThread alloc] initWithTarget:self selector:@selector(runRequest) object:nil];
                [thread setName:@"com.imooc.thread"];
                //启动
                [thread start];
            }
        }
    }
    return thread;
}
- (void)runRequest{
    //创建一个source
    CFRunLoopSourceContext context = {0,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
    CFRunLoopSourceRef source = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context);
    //创建RunLoop,同时向RunLoop的DefaultMode下面添加Source
    CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
    //如果可以运行
    while (runAlways) {
        @autoreleasepool {
          //令当初RunLoop运行在DefaultMode下面
            CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1.0e10,true);
        }
    }
    //某一时机 静态变量 runAlways = NO时,可以保证跳出RunLoop,线程退出
    CFRunLoopRemoveSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
    CFRelease(source);
}
@end

6.问题总结

(1)什么是RunLoop,它是怎样做到有事做事,没事休息的?

RunLoop实际是一个事件循环,用于处理事件和消息以及对它们进行管理。由于在调用CFRunLoopRun之后会调用系统的mach_msg()函数,同时发生了从用户态向核心态的切换,然后当前线程处于休眠状态,所以可以做到有事做时,做事没事做时休息。

(2)RunLoop与线程是怎样的关系?

a.runloop与线程是一一对应的关系
b.一个线程默认是没有runloop的,需要手动创建。

(3)实现一个常驻线程

我们可以通过三个步骤,第一个步骤呢,创建一个线程对应的runloop,之后向这个runloop中添加source、timer、observer、port等内容,第三步调用CFRunLoop的一个run方法就可以实现一个常驻线程。在具体使用的过程中,需要注意,运行的模式和资源添加的模式必须是同一个,否则应为外部使用了while循环,就导致了一个死循环

(4)怎样保证子线程数据回来更新UI的时候不打断用户的滑动操作?

在用户进行滑动过程中,当前的runloop运行在UITrackingRunLoopMode,我们对网络请求一般放在子线程中进行的,而子线程返回给主线程的数据呢,我们要抛给主线程,用来更新UI,这个时候我们可以通过把子线程抛会给主线程更新UI的逻辑包装起来,给它提交到主线程的default模式下面,这样的话,抛回来的任务,当前用户正在滑动过程中处于UITrackingRunLoopMode模式下,我们分派到defalut的模式下的任务就不会执行,而当我们手停止滑动操作之后,当前线程它的mode切换到了,default模式下,这个时候处理子线程上抛给主线程的任务,对它进行处理,这样就不会打断用户的滑动操作。

上一篇 下一篇

猜你喜欢

热点阅读