欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

iOS课程观看笔记(七)---RunLoop

程序员文章站 2024-03-24 21:30:16
...

iOS课程观看笔记(七)---RunLoop

GCD的内部原来,线程池
RunLoop与RunTime

什么是RunLoop?

RunLoop是通过内部维护的事件循环来对 事件/消息 进行管理的 对象
事件循环包括两点:
没有消息需要处理时,休眠以避免资源占用
有消息需要处理时,立刻被唤醒

iOS课程观看笔记(七)---RunLoop

RunLoop的关键点,就是用户态与内核态的切换

问:为什么iOS中main()函数可以保持一直运行状态。而不退出?

iOS课程观看笔记(七)---RunLoop

在main()函数内部,会调用UIApplicationMain()函数,在UIApplicationMain()函数内部会启动主线程的RunLoop,RunLoop通过内部维护的事件循环来对 事件/消息 进行管理,能做到有事做的时候去做事,没事做的时候,通过用户态到内核态的切换,进行休眠,从而避免资源浪费。

RunLoop如何维护事件循环机制呢?


RunLoop的数据结构

苹果提供了两套RunLoop:NSRunLoop和CFRunLoop

CFRunLoop是Core Foundation框架的,CF开头的框架是开源的
NSRunLoop是Foundation框架的

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

CFRunLoop
CFRunLoopModel
Source/Timer/Observer

苹果CFRunLoop开源地址

iOS课程观看笔记(七)---RunLoop

CFRunLoopSource

Source0
需要手动唤醒线程
触摸事件处理
performSelector:onThread:

Source1
具备唤醒线程的能力
基于Port的线程间通信
系统事件捕捉

CFRunLoopTimer

基于事件的定时器
和NSTimer是 toll-free bridged(免费桥转换)的

CFRunLoopObserver

问:我们可以监听RunLoop的哪些时间点?

iOS课程观看笔记(七)---RunLoop

kCFRunLoopBeforeWaiting:waiting等待、休眠。是用户态到内核态的转换
kCFRunLoopAfterWaiting:是内核态到用户态的转换

iOS课程观看笔记(七)---RunLoop
线程和RunLoop是一对一的关系
RunLoop跟Model是一对多的关系
Model和Source/Timer/Observer也是一对多的关系

一个RunLoop包含若干个Mode,每个Mode又包含若干个source0、source1、observer、timer
RunLoop启动时只能选择其中一个Mode作为currentMode。
如果需要切换Mode,只能退出当前loop,重新选择一个Mode进入。
不同组的source0、source1、observer、timer能分隔开来,互不影响
如果Mode里没有任何source0、source1、observer、timer,RunLoop会立马退出

CFRunLoopCommonModes

CFRunLoopCommonModes并不是实际存在的一种Mode
commonMode是同步Source/Timer/Observer到多个Mode中的一种技术方案

问:点击App图标,从启动到杀死进程,中间经历了哪些?

从大的方面,经历了程序启动的三个方面:dyld、runtime、main函数
还可以从RunLoop的角度去分析

iOS课程观看笔记(七)---RunLoop
iOS课程观看笔记(七)---RunLoop

RunLoop和NSTimer

iOS课程观看笔记(七)---RunLoop
两种方法:
方法一:

NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 repeats:YES block:^(NSTimer * _Nonnull timer) {
        NSLog(@"123");
    }];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

方法二:

void CFRunLoopAddTimer(CFRunLoopRef rl, CFRunLoopTimerRef timer, CFRunLoopMode mode);

RunLoop与多线程

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

问:怎样实现一个常驻线程?

为当前线程开启一个RunLoop
向该RunLoop中添加一个Port或者Source维护RunLoop的事件循环
启动该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

iOS课程观看笔记(七)---RunLoop

问:怎么保证子线程数据回来更新UI的时候,不打断用户的滑动操作?

滑动是在UITrackingRunloopMode下,滑动结束了,runloop由UITrackingRunloopMode又回到defaultMode下了。
数据加载一般在子线程下载,下载完毕后在主线程进行UI刷新。
可以将子线程数据,给主线程刷新UI的时候,包装后提交到主线程的defaultModel下,这样两个model不会同时执行,也就不会打断用户的滑动操作。

[self performSelectorOnMainThread:@selector(updateUI) withObject:nil waitUntilDone:NO modes:@[NSDefaultRunLoopMode]];

相关标签: iOS课程观看笔记