现在对iOS开发者要求越来越高,RunLoop其实在开发中很少会用到但是也需要我们去了解。
RunLoop简单介绍
RunLoop其实就是一个简单的运行循环,保持程序的持续运行,处理App各种事件(比如触摸事件,定时事件,Selector事件),RunLoop的一个特性是该做事的时候做事,该休息的时候休息。这样可以节省CPU资源,提高程序性能。
RunLoop处理逻辑.png
RunLoop的类
- CFRunLoopRef
- CFRunLoopModeRef
- NSDefaultRunLoopMode :默认模式(当界面有拖动的时候,不会执行加入此RunLoop里面方法)
- UITrackingRunLoopMode: 界面追踪模式(当界面有拖动的时候,执行其中方法)
- NSRunLoopCommonModes:NSDefaultRunLoopMode + UITrackingRunLoopMode(不管是否拖动都会执行其中方法)
- CFRunLoopSourceRef
- Source0:非基于Port的(用户调用的事件)
- Source1:基于Port的(系统调用的事件)
- CFRunLoopTimerRef
-
CFRunLoopOBserverRef
RunLoop结构.png每个RunLoop都有需要一个自己的运行模式(Model),每个模式里面至少有一个Source或Timer,也可以添加Observer。
RunLoop对象
iOS有2套API来访问RunLoop:
- NSRunLoop
这个是基于CFRunLoopRef的一层OC包装。//1.获得主线程对应的runloop NSRunLoop *mainRunLoop = [NSRunLoop mainRunLoop]; //2.获得当前线程对应的runLoop NSRunLoop *currentRunLoop = [NSRunLoop currentRunLoop];
- CFRunLoopRef
//1.获得主线程对应的runloop CFRunLoopGetMain() //2.获得当前线程对应的runLoop CFRunLoopGetCurrent()
RunLoop与线程
RunLoop和线程是一一对应的,主线程的runloop已经默认是开启的,但是子线程的需要手动开启。
//获取runloop
NSRunLoop *currentRunloop = [NSRunLoop currentRunLoop];
//开启runloop
[currentRunloop run];//这里开启的条件是需要给RunLoop添加一个Source或Timer。
RunLoop的观察者
添加观察者能够监控RunLoop状态的改变
//1.创建监听者
/*
第一个参数:怎么分配存储空间
第二个参数:要监听的状态 kCFRunLoopAllActivities 所有的状态
第三个参数:时候持续监听
第四个参数:优先级 总是传0
第五个参数:当状态改变时候的回调
*/
CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
//activity表示不同的状态
kCFRunLoopEntry = 即将进入runloop
kCFRunLoopBeforeTimers = 即将处理timer事件
kCFRunLoopBeforeSources = 即将处理source事件
kCFRunLoopBeforeWaiting = 即将进入睡眠
kCFRunLoopAfterWaiting = 被唤醒
kCFRunLoopExit = runloop退出
kCFRunLoopAllActivities
});
//添加观察者
/*
第一个参数:要监听哪个runloop
第二个参数:观察者
第三个参数:运行模式
*/
CFRunLoopAddObserver(CFRunLoopGetCurrent(),observer, kCFRunLoopDefaultMode);
RunLoop的应用场景
- 定时器
//1.创建定时器 NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES]; //2.添加定时器到runLoop中,指定runloop的运行模式为 /* 第一个参数:定时器 第二个参数:runloop的运行模式 NSDefaultRunLoopMode:默认(当界面有拖动的时候,不会执行其方法) UITrackingRunLoopMode:界面追踪(当界面拖动的时候执行其中方法) NSRunLoopCommonModes:NSDefaultRunLoopMode + UITrackingRunLoopMode(不管是否拖动都会执行其方法) */ [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
- 定时器第二种用法
//该方法内部自动添加到runloop中,并且设置运行模式为默认 [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];
- 常驻线程
场景是当我们需要一个一直运行的子线程来做一些事情的时候。//1.创建线程 self.thread = [[NSThread alloc]initWithTarget:self selector:@selector(task1) object:nil]; [self.thread start]; //2.在线程方法让子线程的RunLoop跑起来 -(void)task1 { //1.获得子线程对应的runloop NSRunLoop *runloop = [NSRunLoop currentRunLoop]; //2.需要给runloop添加一个源保证其不退出 [runloop addPort:[NSPort port] forMode:NSDefaultRunLoopMode]; //3.开启runloop [runloop run]; }
网友评论