#import "ViewController.h"
@interface ViewController ()
@property(nonatomic, assign) BOOL stopFlag;
@end
@implementation ViewController
//Run loop就是一个事件处理的循环,用来不停的调动工作以及处理输入事件。使用Run loop的目的就是节省CPU效率,线程在有工作的时候忙于工作,而没工作的时候处于休眠状态。
//何时使用Run loop:对于辅助线程,在需要和线程有更多的交互时,才使用Run loop。比如使用端口或者自定义输入源和其它线程通讯、使用线程定时器、Cocoa中使用performSelector 的方法(Performing selectors on other threads)、使线程周期性工作。
//Run loop有两种来源:输入源和定时源。输入源传递异步事件,通常消息来自于其他线程或程序。输入源的种类:基于端口的输入源和自定义输入源。定时源则传递同步事件,发生在特定时间或者重复的时间间隔。
- (void)viewDidLoad {
[super viewDidLoad];
// // Do any additional setup after loading the view, typically from a nib.
// //使用Run loop对象提供了添加输入源、定时器和Run loop的观察者以及启动Runloop的接口,使用Run loop包括获取--配置--启动--退出四个过程。
// //1、获取Run loop的对象
// //A、通过NSRunLoop获取
// //获得当前thread的Run loop
// NSRunLoop *myRunLoop = [NSRunLoop currentRunLoop];
// //将Cocoa的NSRunLoop类型转换成core Foundation的CFRunLoopRef类型
// CFRunLoopRef c = [myRunLoop getCFRunLoop];
// //开辟新线程
// [NSThread detachNewThreadSelector:@selector(newThreadProcess) toTarget:self withObject:nil];
_stopFlag = NO;
NSLog(@"Start a new thread.");
[NSThread detachNewThreadSelector: @selector(newThreadProc)
toTarget: self
withObject: nil];
while (!_stopFlag) {
NSLog(@"Beginrunloop");
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
beforeDate: [NSDate distantFuture]];
NSLog(@"Endrunloop.");
}
NSLog(@"OK");
}
- (void)newThreadProcess{
@autoreleasepool {
//获得thread的RunLoop
NSRunLoop *myRunLoop = [NSRunLoop currentRunLoop];
//设置Run loop observer的运行环境
CFRunLoopObserverContext context = {0,(__bridge void *)(self),NULL,NULL,NULL};
//创建Run loop observer对象
//第一个参数用于分配observer对象的内存
//第二个参数用以设置observer所要关注的事件,详见回调函数myRunLoopObserver中注释
//第三个参数用于标识该observer是在第一次进入runloop时执行还是每次进入run loop处理时均执行
//第四个参数用于设置该observer的优先级
//第五个参数用于设置该observer的回调函数
//第六个参数用于设置该observer的运行环境
CFRunLoopObserverRef observer = CFRunLoopObserverCreate(kCFAllocatorDefault, kCFRunLoopAllActivities, YES, 0, &myRunLoopObserver, &context);
if(observer)
{
//将Cocoa的NSRunLoop类型转换成CoreFoundation的CFRunLoopRef类型
CFRunLoopRef cfRunLoop = [myRunLoop getCFRunLoop];
//将新建的observer加入到当前thread的runloop
CFRunLoopAddObserver(cfRunLoop, observer, kCFRunLoopDefaultMode);
}
//定时器每隔一秒执行一次方法
[NSTimer scheduledTimerWithTimeInterval: 1
target: self
selector:@selector(timerProcess)
userInfo: nil
repeats: YES];
NSInteger loopCount = 2;
do{
//启动当前thread的loop直到所指定的时间到达,在loop运行时,runloop会处理所有来自与该run loop联系的inputsource的数据
//对于本例与当前run loop联系的inputsource只有一个Timer类型的source。
//该Timer每隔1秒发送触发事件给runloop,run loop检测到该事件时会调用相应的处理方法。
//由于在run loop添加了observer且设置observer对所有的runloop行为都感兴趣。
//当调用runUnitDate方法时,observer检测到runloop启动并进入循环,observer会调用其回调数,第二个参数所传递的行为是kCFRunLoopEntry。
//observer检测到runloop的其它行为并调用回调函数的操作与上面的描述相类似。
[myRunLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:5.0]];
//当run loop的运行时间到达时,会退出当前的runloop。observer同样会检测到runloop的退出行为并调用其回调函数,第二个参数所传递的行为是kCFRunLoopExit。
loopCount--;
}while (loopCount);
}
}
void myRunLoopObserver(CFRunLoopObserverRef observer,CFRunLoopActivity activity, void *info){
switch (activity) {
case kCFRunLoopEntry:
NSLog(@"run loop entry");
break;
case kCFRunLoopBeforeTimers:
NSLog(@"run loop before timers");
break;
case kCFRunLoopBeforeSources:
NSLog(@"run loop before sources");
break;
case kCFRunLoopBeforeWaiting:
NSLog(@"run loop before waiting");
break;
case kCFRunLoopAfterWaiting:
NSLog(@"run loop after waiting");
break;
case kCFRunLoopExit:
NSLog(@"run loop exit");
break;
default:
break;
}
}
- (void)timerProcess{
for (int i=0; i<5; i++) {
NSLog(@"In timerProcess count = %d.", i);
sleep(1);
}
}
//----------------------------
//while循环后执行的语句会在很长时间后才被执行。因为,改变变量StopFlag的值,runloop对象根本不知道,runloop在这个时候未被唤醒。有其他事件在某个时点唤醒了主线程,这才结束了while循环,但延缓的时长总是不定的。
//缩短runloop的休眠事件是不合适的,因为这样会导致runloop被经常唤醒,违背了runloop的设计初衷。runloop就是为了提供效率,有工作时忙于工作,没工作时处于休眠状态。
//可以改为向主线程发送消息,唤醒runloop。
-(void)newThreadProc{
NSLog(@"Enter newThreadProc.");
for (int i=0; i<10; i++) {
NSLog(@"InnewThreadProc count = %d.", i);
sleep(1);
}
// _stopFlag = YES;
[self performSelectorOnMainThread: @selector(setEnd)
withObject: nil
waitUntilDone: NO];
NSLog(@"Exit newThreadProc.");
}
-(void)setEnd{
_stopFlag = YES;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end