runloop使用

#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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值