RunLoop

2016-04-28  本文已影响81人  月下独酌灬

RunLoop

作用

模式

模拟 RunLoop 实现

void callFunc(int num) {
    NSLog(@"正在执行 %d 功能...",num);
}
int main(int argc, const char * argv[]) {
    @autoreleasepool {

        int result = 0;

        while (YES) {

            printf("请输入选项,O表示退出");

            // 阻塞式 : 需要控制台输入值才能继续运行
            scanf("%d",&result);

            if (0==result) {
                NSLog(@"程序正常退出");
                break;
            } else {
                callFunc(result);
            }
        }
    }
    return 0;
}

运行循环与时钟

- (void)viewDidLoad {
    [super viewDidLoad];

    // 定时器 : 添加了滚动事件之后,定时器就不再执行了
//    [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(fire) userInfo:nil repeats:YES];

    NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(fire) userInfo:nil repeats:YES];
    // timerWithTimeInterval 创建时钟时,需要将定时器添加到运行循环中
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
}

时钟的执行方法入口

- (void)fire
{
    // 不能使用 sleep
//    [NSThread sleepForTimeInterval:1.0];

    // 耗时操作
    for (int i = 0; i < 1000*1000; i++) {
        NSString *str = [NSString stringWithFormat:@"hello %d",i];
    }

    static int num = 0;
    num++;
    NSLog(@"%d",num);
}

运行测试,会发现卡顿非常严重

将时钟添加到子线程中工作

/// 线程
@property (nonatomic,strong) NSThread *thread;
- (void)viewDidLoad {
    [super viewDidLoad];

    self.thread = [[NSThread alloc] initWithTarget:self selector:@selector(demo) object:nil];
    [self.thread start];
}
- (void)demo
{
    NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(fire) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];

    // 启动当前线程的运行循环;当前线程的运行循环是个不同于while的死循环
//    [[NSRunLoop currentRunLoop] run];
    CFRunLoopRun();

    NSLog(@"over");
}
// 停止当前运行循环
CFRunLoopStop(CFRunLoopGetCurrent());

按钮点击

创建按钮

- (void)viewDidLoad {
    [super viewDidLoad];

    UIButton *addBtn = [UIButton buttonWithType:UIButtonTypeContactAdd];
    [self.view addSubview:addBtn];
    addBtn.center = self.view.center;

    // 向 runloop 注册监听,点击按钮,执行 ViewController 的 click 方法
    [addBtn addTarget:self action:@selector(click) forControlEvents:UIControlEventTouchUpInside];
}

点击方法

- (void)click
{
    NSLog(@"%s",__FUNCTION__);
}

时间循环图解按钮点击

图解按钮点击.png

RunLoop-主线程

代码实现

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [self timerDemo];
}

- (void)timerDemo
{
    // 创建定时器
    NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(fire) userInfo:nil repeats:YES];

    // 将定时器添加到消息循环
    // currentRunLoop : 获取到当前的消息循环
    // forMode : 当前定时源timer的运行模式
    // NSRunLoopCommonModes : 模式组,里面包含了几种运行模式,kCFRunLoopDefaultMode / UITrackingRunLoopMode
    // 消息循环也是运行在一个模式下面的,默认的模式是kCFRunLoopDefaultMode,只有定时源的运行模式和消息循环的运行模式保持一致,定时源对应的方法才能执行
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
}

- (void)fire
{
    NSLog(@"hello %@",[NSRunLoop currentRunLoop].currentMode);
}

RunLoop-子线程

代码实现

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
//    [self timerDemo];

    NSLog(@"start");

    [self performSelectorInBackground:@selector(timerDemo) withObject:nil];
}

- (void)timerDemo
{
    //创建定时器(定时源)
    NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(fire) userInfo:nil repeats:YES];

    // 获取当前的消息循环
    // currentRunLoop : 当前子线程的消息循环
    // 子线程的消息循环默认是不开启的,需要我们手动开启
    // 子线程中的运行模式和主线程是一样的
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];

    // 手动开启子线程的消息循环
    // run : 消息循环不停止的话,后面的代码永远不会被执行的
    // runUntilDate : 消息循环运行到指定的日期之后就自动的停止
    [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:5.0]];

    //  提问 : over能够打印出来吗?
    NSLog(@"over");
}

- (void)fire
{
    NSLog(@"hello");
}

RunLoop.jpg
上一篇 下一篇

猜你喜欢

热点阅读