Runloop

103 阅读1分钟

Runloop可以做什么?

  • 处理Crash
  • 保持线程存活(线程保活)
  • 监测、优化卡顿

子线程执行完任务之后会自动销毁

线程跟Runloop有什么关系?

线程跟Runloop一一对应,并且是以键值对存储的(线程:Runloop => key:value)

Runloop的组成

Runloop的组成:Mode->sources/timer/observer (observer负责观察runloop的状态,对runloop的启动和休眠不起作用)

如果Runloop的Mode里面没有sources、timer的话,Runloop会直接进入休眠状态

sources1:基于port的内核事件,可以主动唤醒 (数据结构:machport:sources1)

sources0:非基于port,不能主动唤醒 (数据结构:数组)


#mark pragma - 线程保护
-(IBAction)keepAliveAction:(UIButton *)sender{
    static dispatch_once_t onceToken;
    self.stop = NO;
    dispatch_once(&onceToken, ^{
        testThread = [[MyThread alloc] initWithTarget:self selector:@selector(doSomething) object:nil];
        [testThread setName:@"线程保活"];
        [testThread start];
    })
}

-(void)doSomething{
    @autoreleasepool{
    NSLog(@"%@",[NSThread currentThread]); // testThread
    NSRunloop *runloop = [NSRunloop currentRunloop];
    // 添加port或者timer来唤醒runloop(如果不添加,runloop将进入休眠)
    [runloop addPort:[NSMachPort port] forMode:NSRunloopCommonModes]; // sources1
    // [runloop addTimer: forMode:]
    // CFRunloopAddSource()
    // 使用[runloop runMode: beforeDate:] 代替 [runloop run],设置一个布尔值来
    while(!self.stop) {
       [runloop runMode:NSDefaultRunloopMode beforeDate:[NSDate distantFuture]]; 
    }
    // [runloop run];
    NSlog(@"结束"); // runloop被唤醒则不会执行到这一行(如果runloop进入休眠,则会打印结束)
}

#mark pragma - 执行任务
-(IBAction)performTask:(UIButton *)sender{
    [self performSelector:@selector(addSubThreadAction) onThread:testThread withObject:nil waitUntilDone:NO];
}

-(void)addSubThreadAction{
    // 线程保活需要做的操作写到这里
    
    // 停止 (只能停止单次循环,run方法会多次调用runMode: beforeDate:)
    self.stop = YES;
    testThread = nil; // 停止强引用
    CFRunloopStop(CFRunloopGetCurrent());
}

NSRunloop和CFRunloopRef的区别:

  • CFRunloopRef纯C语言实现,线程安全;
  • NSRunloop是面向对象的,不是线程安全的。

image.png