iOS收藏OC底层相关iOS

iOS之RunLoop详解

2019-03-12  本文已影响330人  云霄_云霄

1.RunLoop的介绍:

RunLoop即运行循环(跑圈),只不过它这种循环比较高级。一般的 while 循环会导致 CPU 进入忙等待状态,而 RunLoop 则是一种“闲”等待,这部分可以类比 Linux 下的 epoll。当没有事件时,RunLoop 会进入休眠状态,有事件发生时, RunLoop 会去找对应的 Handler 处理事件。RunLoop 可以让线程在需要做事的时候忙起来,不需要的话就让线程休眠。

2.RunLoop的基本作用:

3.iOS程序入口与RunLoop的关系:

int main(int argc, char * argv[]) {
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

由于main函数里面UIApplicationMain启动了一个RunLoop,所以UIApplicationMain函数一直没有返回,则程序并不会马上退出,而是保持持续运行状态,这个默认的RunLoop是跟主线程相关联的。

4.RunLoop对象:

5.RunLoop与线程:

6.获取RunLoop对象:

    //Foundation框架下
    NSRunLoop * currentRunLoop =  [NSRunLoop currentRunLoop]; //获取当前线程的RunLoop对象
    NSRunLoop * mainRunLoop = [NSRunLoop mainRunLoop]; //获取主线程的RunLoop对象
    
    //Core Foundation框架下
    /*
    CFRunLoopRef * currentRunLoop =  CFRunLoopGetCurrent() //获取当前线程的RunLoop对象
    CFRunLoopRef * mainRunLoop = CFRunLoopGetMain() //获取主线程的RunLoop对象
    */

7.RunLoop的相关类:

CFRunLoopModeRef的详解:

8.RunLoop的运行模式和Timer:

-(void)timer{
    //01-创建定时对象
    NSTimer * timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];
    //02-把定时器添加到RunLoop中(切记:如果当前方法在子线程,需要手动开启当前子线程的RunLoop,并且开启,而且开启方法要在添加定时器之后,否则开启了因为没有事件就直接停止了)
    //(情况1)模式为默认:NSDefaultRunLoopMode--当滚动UItextView的时候定时器停止工作
    //[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
    
    //(情况2)界面追踪模式为:UITrackingRunLoopMode--(只有当滚动UItextView的时候定时器才工作)
    //[[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];
    
    //(情况3)界面追踪模式为:NSRunLoopCommonModes(NSDefaultRunLoopMode|UITrackingRunLoopMode)--(不管有没有滚动,定时器一直工作)
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
    
}
-(void)run{
    NSLog(@"%@",[NSRunLoop currentRunLoop].currentMode);
}

9.CFRunLoopObserverRef的详解:

/*
     01-创建观察者
     参数说明
     第一个参数:分配存储空间
     第二个参数:要监听的状态
     第三个参数:是否持续监听
     第四个参数:0
     第五个参数:block回调,当runloop状态改变的时候会调用
     输出:
     2019-03-12 15:13:08.598453+0800 SmallProgram[3374:145215] runloop即将处理Timers事件
     2019-03-12 15:13:08.598653+0800 SmallProgram[3374:145215] runloop即将处理Sources事件
     2019-03-12 15:13:08.598906+0800 SmallProgram[3374:145215] runloop即将处理Timers事件
     2019-03-12 15:13:08.599048+0800 SmallProgram[3374:145215] runloop即将处理Sources事件
     2019-03-12 15:13:08.599180+0800 SmallProgram[3374:145215] runloop即将处理Timers事件
     2019-03-12 15:13:08.599295+0800 SmallProgram[3374:145215] runloop即将处理Sources事件
     2019-03-12 15:13:08.599620+0800 SmallProgram[3374:145215] runloop即将进入到休眠
     2019-03-12 15:13:08.693981+0800 SmallProgram[3374:145215] runloop被唤醒
     2019-03-12 15:13:08.694216+0800 SmallProgram[3374:145215] runloop即将处理Timers事件
     2019-03-12 15:13:08.694340+0800 SmallProgram[3374:145215] runloop即将处理Sources
     */
    CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
    
        switch (activity) {
            case kCFRunLoopEntry:
                NSLog(@"runloop启动");
                break;
            case kCFRunLoopBeforeTimers:
                NSLog(@"runloop即将处理Timers事件");
                break;
            case kCFRunLoopBeforeSources:
                NSLog(@"runloop即将处理Sources事件");
                break;
            case kCFRunLoopBeforeWaiting:
                NSLog(@"runloop即将进入到休眠");
                break;
            case kCFRunLoopAfterWaiting:
                NSLog(@"runloop被唤醒");
                break;
            case kCFRunLoopExit:
                NSLog(@"runloop退出");
                break;
                
            default:
                break;
        }
    });
    /*
    //02-监听runLoop的状态
     参数说明
     第一个参数:runLoop对象
     第二个参数:监听者
     第三个参数:runLoop在哪种模式下的状态(这里要写C情况下的状态)
               kCFRunLoopDefaultMode
    */
    CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);

10.RunLoop的应用:

-(void)application{
    
    NSThread * thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
    [thread start];
    self.thread = thread;
    
}
-(void)run{
    
    //01子线程的RunLoop需要手动创建并启动
    //02RunLoop启动后会选择运行模式,判断运行模式是否为空
    NSRunLoop * runLoop = [NSRunLoop currentRunLoop];
    //(方法一)往运行模式中添加timer
    //[NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:@selector(timeRun) userInfo:nil repeats:YES];
    //(方法二)往运行模式中添加source=port|custom|selector
    [runLoop addPort:[NSPort port] forMode:NSDefaultRunLoopMode];
    
    [runLoop run];
    
}
//将下面方法放到需要子线程来做任务的事件中,比如点击按钮事件
//按钮点击事件让子线程来执行任务run2
    [self performSelector:@selector(run2) onThread:self.thread withObject:nil waitUntilDone:YES];
//这样self.thread会一直不死,来等待处理run2的事件

11.RunLoop的内部自动释放池:

本文参考:
线程、自动释放池、RunLoop的爱恨情仇https://www.jianshu.com/p/8b011b844231

上一篇下一篇

猜你喜欢

热点阅读