一.RunLoop基本概念
概念:程序的运行循环,通俗的来说就是跑圈.
1. 基本作用(作用重大)
(1) 保持程序的持续运行(ios程序为什么能一直活着不会死)
(2) 处理app中的各种事件(比如触摸事件、定时器事件【NSTimer】、selector事件【选择器·performSelector···】)
(3)节省CPU资源,提高程序性能,有事情就做事情,没事情就休息
2. 重要说明
(1)如果没有Runloop,那么程序一启动就会退出,什么事情都做不了。
(2)如果有了Runloop,那么相当于在内部有一个死循环,能够保证程序的持续运行
3.main函数中的Runloop
(1) 在UIApplication函数内部就启动了一个Runloop,该函数返回一个int类型的值
(2) 这个默认启动的Runloop是跟主线程相关联的
4.Runloop对象
(1)在iOS开发中有两套api来访问Runloop
第一种:foundation框架【NSRunloop】
第二种:core foundation框架【CFRunloopRef】
(2)NSRunLoop和CFRunLoopRef都代表着RunLoop对象,它们是等价的,可以互相转换
(3)NSRunLoop是基于CFRunLoopRef的一层OC包装,所以要了解RunLoop内部结构,需要多研究CFRunLoopRef层面的API(Core Foundation层面)
(1) Runloop和线程的关系:一个Runloop对应着一条唯一的线程
问题:如何让子线程不死
回答:给这条子线程开启一个Runloop
(2) Runloop的创建:主线程Runloop已经创建好了,子线程的runloop需要手动创建
(3) Runloop的生命周期:在第一次获取时创建,在线程结束时销毁
(4) 拿到当前应用程序的主Runloop(主线程对应的Runloop)
NSRunLoop *mainLoop = [NSRunLoopmainRunLoop];
CFRunLoopRef *mainLoop =CFRunLoopGetMain();
RunLoop五个相关的类
- CFRunloopRef
- CFRunloopModeRef【Runloop的运行模式】
- CFRunloopSourceRef【Runloop要处理的事件源】
- CFRunloopTimerRef【Timer事件】
-
CFRunloopObserverRef【Runloop的观察者(监听者)】
以下是五个相关类的抛析:
(1) CFRunloopModeRef代表着Runloop的运行模式
(2) 一个Runloop中可以有多个mode,一个mode里面又可以有多个source\observer\timer等等
(3) 每次runloop启动的时候,只能指定一个mode,这个mode被称为该Runloop的当前mode
(4) 如果需要切换mode,只能先退出当前Runloop,再重新指定一个mode进入
(5) 这样做主要是为了分割不同组的定时器等,让他们相互之间不受影响
(6) 系统默认注册了5个mode
第一种模式: kCFRunLoopDefaultMode:App的默认Mode,通常主线程是在这个Mode下运行
第二种模式: UITrackingRunLoopMode:界面跟踪 Mode,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响
第四种模式: GSEventReceiveRunLoopMode: 接受系统事件的内部 Mode,通常用不到
第五种模式: kCFRunLoopCommonModes: 这是一个占位用的Mode,不是一种真正的Mode
-
CFRunloopTimerRef
(1) runloop一启动就会选中一种模式,当选中了一种模式之后其它的模式就不会参与。一个mode里面可以添加多个NSTimer,也就是说以后当创建NSTimer的时候,可以指定它是在什么模式下运行的。
(2) 它是基于时间的触发器,说直白点那就是时间到了我就触发一个事件,触发一个操作。基本上说的就是NSTimer .
(3) 相关代码 / - (void)timer2 { //NSTimer 调用了scheduledTimer方法,那么会自动添加到当前的runloop里面去,而且runloop的运行模式kCFRunLoopDefaultMode
/** * 1:Runloop和线程的关系:1:一一对应,主线程的runloop已经默认创建,但是子线程的需要手动创建:创建子线程的runloop: NSRunLoop *run = [NSRunLoop currentRunLoop];currentRunLoop懒加载的,在同一个子线程中创建多个runloop,则返回的都是同一个对象,因为其是懒加载模式的 2:在runloop中有多个运行模式,但是runloop只能选择一种模式运行,mode里面至少要有一个timer或者是source 2:1.获得主线程对应的runloop:NSRunLoop *mainRunLoop = [NSRunLoop mainRunLoop]; 2:获得当前线程对应的runLoop:NSRunLoop *currentRunLoop = [NSRunLoop currentRunLoop]; 3:CFRunLoop:1:获得主线程对应的runloop:CFRunLoopGetMain() 2:获得当前线程对应的runLoop:CFRunLoopGetCurrent() * */

系统默认注册了5个Mode:
1.KCFRunLoopDefaultMode:App默认的Mode,通常主线程在这个Mode下运行
2.UITrackingRunLoopMode:界面跟踪Mode,用于ScrollView追踪触摸滑动,保证界面滑动是不受其他Mode 影响
/**
* 1:NSLog(@"%@",[NSRunLoop currentRunLoop]);打印当前线程的RunLoop,懒加载模式,一条线程对应一个RunLoop对象,有返回,没有创建,主线程的RunLoop默认创建,子线程的RunLoop需要手动创建,[NSRunLoop currentRunLoop],同一个线程中若是创建多个RunLoop,则返回的都是同一个RunLoop对象,一个RunLoop里会有多个mode运行模式(系统提供了5个),但运行时只能指定一个RunLoop,若是切换RunLoop,则需要退出当前的RunLoop
2:定时器NSTimer问题:1.若是创建时用timerWithTimeInterval,需要手动将定时器添加到NSRunLoop中,指定的模式为Default,但是如果有滚动事件的时候,定时器就会停止工作。更改NSRunLoop的运行模式,UITRackingRunLoopMode界面追踪,此模式是只有发生滚动的时候才会开启定时器:NSRunLoopCommonModes = NSDefaultRunLoopMode + UITrackingRunLoopMode
**/
下面我来上传一段代码来证明一下
- (void)viewDidLoad {
[super viewDidLoad];
UIScrollView *scrollView = [[UIScrollView alloc]initWithFrame:CGRectMake(0, 0, 375, 500)];
scrollView.backgroundColor = [UIColor redColor];
scrollView.delegate = self;
scrollView.contentSize = CGSizeMake(1000, 500);
[self.view addSubview:scrollView];
// Do any additional setup after loading the view, typically from a nib.
}
-(void)scrollViewDidScroll:(UIScrollView *)scrollView{
[self timer1];
}
-(void)timer1{
//创建定时器
NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(run1) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop]addTimer:timer forMode:NSRunLoopCommonModes];
}
-(void)run1{
NSLog(@"run------%@------%@",[NSThread currentThread],[NSRunLoop currentRunLoop].currentMode);
}
如果是NSRunLoopCommonModes这种类型性的如果滑动Scrollview结果:
RunLoopAndTimer[26057:7554861] run------<NSThread: 0x17406c340>{number = 1, name = main}------UITrackingRunLoopMode
2017-04-18 18:18:52.849328 RunLoopAndTimer[26057:7554861] run------<NSThread: 0x17406c340>{number = 1, name = main}------kCFRunLoopDefaultMode
两种类型都能打印出来如果是NSDefaultRunLoopMode这种类型性的如果滑动Scrollview结果:
<NSThread: 0x17406c780>{number = 1, name = main}------kCFRunLoopDefaultMode
2017-04-18 18:22:15.675135 RunLoopAndTimer[26063:7556027] run------<NSThread: 0x17406c780>{number = 1, name = main}------kCFRunLoopDefaultMode
2017-04-18 18:22:15.688838 RunLoopAndTimer[26063:7556027] run------<NSThread: 0x17406c780>{number = 1, name = main}------kCFRunLoopDefaultMode
如果是
UITrackingRunLoopMode这种类型的话只有滑动的时候才会调用
- (void)viewDidLoad {
[super viewDidLoad];
// UIScrollView *scrollView = [[UIScrollView alloc]initWithFrame:CGRectMake(0, 0, 375, 500)];
// scrollView.backgroundColor = [UIColor redColor];
// scrollView.delegate = self;
// scrollView.contentSize = CGSizeMake(1000, 500);
// [self.view addSubview:scrollView];
// Do any additional setup after loading the view, typically from a nib.
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[self timer1];
}
-(void)timer1{
//创建定时器
NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(run1) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop]addTimer:timer forMode:UITrackingRunLoopMode];
}
//调用结果为空白
2173

被折叠的 条评论
为什么被折叠?



