本文共 3625 字,大约阅读时间需要 12 分钟。
1.字面意思:运行循环
2.内部实现:内部是由do-while循环实现的1.保证程序的持续运行
2.处理APP的各种事件(滑动,定时器,selector) 3.节省CPU资源,提高程序性能,让线程有事情做的时候做,没事的时候处于休眠状态。以main函数入口为例:
int main(int argc,char *argv[]){NSLog(@"execute main function");//程序开始return 0;//程序结束}
类似于oc程序,执行完相应的代码之后,程序杀死,不能保证APP的持续运行。
以main函数入口为例
int main(int argc, char *argv[]){do{ NSLog(@"execute main function");//程序开始}while(1)return 0;//程序结束}相当于程序内部有一个死循环,保证程序运行不会中断。
int main(int argh, char *argv[]){ @autoreleasepool{ return UIApplicationMain(argc,argv,nil,NSStringFromClass([AppDelegate class])); }}
在UIApplicationMain函数内部就启动了一个RunLoop,所以UIApplicationMain函数就一直没有返回,保证了程序的持续运行。默认启动的RunLoop是跟主线程相关联的,主要处理与主线程相关的事件。
iOS中有2套API来访问和使用RunLoop
1.每条线程都有唯一的一个与之对应的RunLoop对象。
2.主线程的RunLoop随着程序已自动创建好,但是子线程的RunLoop需要手动创建。 3.获得主线程的RunLopp的方法是[NSRunLoop mainRunLoop]; 4.获得子线程的RunLoop的方法是[NSRunLoop currentRunLoop]; 注意:苹果不允许创建RunLoop,只提供了上述两种获得RunLoop的方法。1.CFRunLoopModeRef
2.CFRunLoopSourceRef 3.CFRunLoopTimeRef 4.CFRunLoopObserverRef 若没有以上几个类,RunLoop是不会循环的。1.代表RunLoop的运行模式。
2.一个RunLoop可以包含若干个mode,每个mode包含若干个Source/Timer/Observer 3.每次RunLoop启动时,只能指定其中的一个Mode,这个Mode被称为currentMode 4.如果需要切换Mode,需要退出RunLoop,再重新指定一个Mode进入。这样做的原因是为了分离不同组Source/Timer/Observer,让其互不影响。 系统注册了5个Mode 1.kCFRunLoopDefaultMode:APP默认Mode,通常主线程是在该Mode下运行的 2.UITrackingRunLoopMode:界面跟踪Mode,用于ScrollView追踪触摸滑动,保证界面滑动时,不受其他mode影响 3.UIInitializationRunLoopMode:在刚启动时App进入的第一个Mode,启动完成后就不再使用。 4.GSEventReceiveRunLoopMode:接受系统事件的内部Mode,通常情况下不用。 5.kCFRunLoopCommonMode:这是一个占位的Mode,不是真正的Mode。基于时间的触发器,基本可以说是NSTimer。
//自动加在runloop下,可以直接运行 // [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];
NSTimer *timer=[NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES]; //只应用于默认模式下 //[[NSRunLoop currentRunLoop]addTimer:timer forMode:NSDefaultRunLoopMode]; //只应用于UITrackingRunLoopMode //[[NSRunLoop currentRunLoop]addTimer:timer forMode:UITrackingRunLoopMode]; //应用于2种模式下,commonmodes是模式的标记,有这个标记的模式有UITrackingRunLoopMode, NSDefaultRunLoopMode。 2种模式有共同的标志,只要把这个标志写上,那么2种模式下都能运行。 [[NSRunLoop currentRunLoop]addTimer:timer forMode:NSRunLoopCommonModes];
CFRunLoopSourceRef 是事件源,也可称为输入源。
1.Port-Based Sources 从其他线程或内核发出的。
2.Custom Input Sources自定义的。(很少用到) 3.CoCoa Perform Selector Sources. (常用)按函数调用栈分类,可分为2类
1.Sources :非基于Port的,常见,比如点击事件 2.Sources1:基于Port的,通过其他线程或者内核通信,接受,分发系统事件。 调用栈其实是栈的一种抽象概念,它表示了方法之间的调用关系。[self performSelector:@selector(run) withObject:nil afterDelay:2 inModes:@[NSRunLoopCommonModes]];
观察者,能够监听RunLoop的状态的改变。
typedef CF_OPTIONS(CFOptionFlags,CFRunLoopActivity){ kCFRunLoopEntry=(1UL<<0),即将进入RunLoop kCFRunLoopBeforeTimers=(1UL<<1),//即将处理Timer kCFRunLoopBeforeSources=(1UL<<2),//即将处理Sources kCFRunLoopBeforeWaiting=(1UL<<5),//即将进入休眠 2的5次方 kCFRunLoopBeforeAfterWaiting=(1UL<<6),//即将从休眠中唤醒 kCFRunLoopExit=(1UL<<7),即将退出RunLoop kCFRunLoopAllActivities=0x0FFFFFFFU//活跃中 } 给RunLoop添加观察者,需要CF类//如果给runLoop添加观察者,需要CF类 CFRunLoopObserverRef observer=CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) { NSLog(@"---%lu---",activity); }); CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);
转载地址:http://vpwin.baihongyu.com/