1. 程式人生 > >CFRunLoop 學習 例子,控制 runloop 時間

CFRunLoop 學習 例子,控制 runloop 時間

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    //這裡偷個懶,直接使用performSelectorInBackground來建立一個執行緒,並執行configRunLoop方法
    [self performSelectorInBackground:@selector(configRunLoop) withObject:nil];
    
    UIButton* __button1 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    [__button1 setTitle:@"Fire Event" forState:UIControlStateNormal];
    //觸發事件啟動RunLoop
    [__button1 addTarget:self action:@selector(triggerEvent) forControlEvents:UIControlEventTouchUpInside];
    __button1.frame = CGRectMake(20, 100, 100, 80);
    [self.view addSubview:__button1];
    
    
    UIButton* __button2 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    [__button2 setTitle:@"Stop RunLoop" forState:UIControlStateNormal];
    //RunLoop週期完成後自動退出執行緒
    [__button2 addTarget:self action:@selector(stopRunloop) forControlEvents:UIControlEventTouchUpInside];
    __button2.frame = CGRectMake(130, 100, 120, 80);
    [self.view addSubview:__button2];
}

- (void)stopRunloop{
    _shouldStop = YES;
}

- (void)triggerEvent{
    if (CFRunLoopIsWaiting(_runLoopRef)) {
        NSLog(@"RunLoop 正在等待事件輸入");
        //新增輸入事件
        CFRunLoopSourceSignal(_source);
        //喚醒執行緒,執行緒喚醒後發現由事件需要處理,於是立即處理事件
        CFRunLoopWakeUp(_runLoopRef);
    }else {
        NSLog(@"RunLoop 正在處理事件");
        //新增輸入事件,當前正在處理一個事件,當前事件處理完成後,立即處理當前新輸入的事件
        CFRunLoopSourceSignal(_source);
    }
}

//此輸入源需要處理的後臺事件
static void fire(void* info __unused){
    NSLog(@"我現在正在處理後臺任務");
    sleep(5);
}

- (void)configRunLoop{
    //這裡獲取到的已經是某個子執行緒了哦,不是主執行緒哦
    _tThread = [NSThread currentThread];
    //這裡也是這個子執行緒的RunLoop哦
    _runLoopRef = CFRunLoopGetCurrent();
    
    bzero(&_source_context, sizeof(_source_context));
    //這裡建立了一個基於事件的源
    _source_context.perform = fire;
    _source = CFRunLoopSourceCreate(NULL, 0, &_source_context);
    //將源新增到當前RunLoop中去
    CFRunLoopAddSource(_runLoopRef, _source, kCFRunLoopCommonModes);
    
    
    while (!_shouldStop) {
        NSLog(@"RunLoop 開始執行");
        //每次RunLoop只執行10秒,每10秒做一次檢測,如果沒有需要處理的後臺任務了,就讓此執行緒自己終止,不用暴力Kill
        CFRunLoopRunInMode(kCFRunLoopDefaultMode, 10, NO);
        NSLog(@"RunLoop 停止執行");
    }
    _tThread = nil;
}


@end

    CFRunLoopSourceRef    _source;
    CFRunLoopSourceContext    _source_context;
    NSThread*              _tThread;
    CFRunLoopRef     _runLoopRef;


@interface ViewController : UIViewController{
    CFRunLoopSourceRef _source;
    CFRunLoopSourceContext _source_context;
    NSThread* _tThread;
    CFRunLoopRef _runLoopRef;
    BOOL _shouldStop;
}


@end