Men的博客

欢迎光临!

0%

RunLoop

概念
数据结构
事件循环机制
RunLoop和NStimer
RunLoop和多线程
RunLoop是通过内部维护的事件循环来对事件/消息进行管理的一个对象
没有消息需要处理时,休眠以避免资源占用
用户态-》核心态
有消息处理时,立即被唤醒
核心态-〉用户态

CFRunLoop
CFRunLoopMode
Source/Timer/Observer

source0
需要手动唤醒线程
source1
具备唤醒线程的能力

CFRunLoopObserver
观测时间点
kCFRunLoopEntry
kCFRunLoopBeforeTimers

CommonMode的特性
NSRunLoopCommonModes
commonMode不是实际存在的一种mode
是同步Source/Timer/Observer到多个Mode中的一种技术方案

如何实现一个常驻线程
给子线程添加RunLoop
@autoreleasepool {
    // 子线程对应的runloop需要自己创建并开启
    // 创建子线程对应的runloop,使子线程一直存在
    NSRunLoop *currentRunloop = [NSRunLoop currentRunLoop];
    // 给runloop添加一个基于port的事件(系统事件),让runloop的运行模式不为空,保证runloop不退出
    [currentRunloop addPort:[NSPort port] forMode:NSDefaultRunLoopMode];
    // 开启运行循环
    [currentRunloop run];
    }
利用 runloop 解释一下页面的渲染的过程?

当我们调用 [UIView setNeedsDisplay] 时,这时会调用当前 View.layer 的 [view.layer setNeedsDisplay]方法。

这等于给当前的 layer 打上了一个脏标记,而此时并没有直接进行绘制工作。而是会到当前的 Runloop 即将休眠,也就是 beforeWaiting 时才会进行绘制工作。

紧接着会调用 [CALayer display],进入到真正绘制的工作。CALayer 层会判断自己的 delegate 有没有实现异步绘制的代理方法 displayer:,这个代理方法是异步绘制的入口,如果没有实现这个方法,那么会继续进行系统绘制的流程,然后绘制结束。

CALayer 内部会创建一个 Backing Store,用来获取图形上下文。接下来会判断这个 layer 是否有 delegate。

如果有的话,会调用 [layer.delegate drawLayer:inContext:],并且会返回给我们 [UIView DrawRect:] 的回调,让我们在系统绘制的基础之上再做一些事情。

如果没有 delegate,那么会调用 [CALayer drawInContext:]。

以上两个分支,最终 CALayer 都会将位图提交到 Backing Store,最后提交给 GPU。

至此绘制的过程结束。

二 你在开发过程中怎么使用RunLoop?什么应用场景?

开启一个常驻线程(让一个子线程不进入消亡状态,等待其他线程发来的消息,处理其他事件)

在子线程中开启一个定时器

在子线程中进行一些长期监控

可以控制定时器在特定模式下运行

可以让某些事件(行为,任务)在特定模式下执行

可以添加observer监听RunLoop的状态,比如监听点击事件的处理(比如在所有点击事件前做一些处理)
1)NSTimer

2)ImageView显示:控制方法在特定的模式下可用

3)PerformSelector

4)常驻线程:在子线程中开启一个runloop

5)自动释放池

   第一次创建:进入runloop的时候

   最后一次释放:runloop退出的时候

   其它创建和释放:当runloop即将休眠的时候会把之前的自动释放池释放,然后重新创建一个新的释放池

// 高性能定时器
__block int timeout=300; //倒计时时间
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_source_t _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0,queue);
dispatch_source_set_timer(_timer,dispatch_walltime(NULL, 0),1.0*NSEC_PER_SEC, 0); //每秒执行
dispatch_source_set_event_handler(_timer, ^{
if(timeout<=0){ //倒计时结束,关闭
dispatch_source_cancel(_timer);
dispatch_async(dispatch_get_main_queue(), ^{
//设置界面的按钮显示 根据自己需求设置
NSLog(@”=====”)
});

}else{
    int minutes = timeout / 60;
    int seconds = timeout % 60;
    NSString *strTime = [NSString stringWithFormat:@"%d分%.2d秒后重新获取验证码",minutes, seconds];
    dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"*******");
    }); 
    timeout--; 
} 

});
dispatch_resume(_timer);