RunLoop

Runloop

运行循环,在程序运行过程中循环做一些事情.

应用范畴:

  • 保持程序的持续运行
  • 定时器 performSelector
  • GCD Async Main Queue
  • 事件响应 手势识别 界面刷新
  • 网络请求
  • AutoreleasePool

Runloop与线程

  • 每条线程都有唯一的一个与之对应的Runloop对象.
  • Runloop保存在一个全局的字典里面,线程最为.key,runloop最为value.
  • 第一次获取的时候自动创建.
  • Runloop线程结束时候销毁.
  • 主线程的Runloop自动创建,子线程默认没有开启Runloop.

获取RunLoop对象

  • Foundation:NSRunloop
  • Core Foundation:CFRunloopRef
    NSRunLoop *runloop;
    CFRunLoopRef runloop2;
    
    runloop = [NSRunLoop currentRunLoop];
    runloop2 = CFRunLoopGetCurrent();
    [NSRunLoop mainRunLoop];//主线程runloop

RunLoop相关的类

  • CFRunLoopRef
  • CFRunLoopModeRef
  • CFRunLoopSourceRef
  • CFRunLoopTimeRef
  • CFRunLoopObserverRef

CFRunLoopRef 底层结构

typedef struct CF_BRIDGED_MUTABLE_TYPE(id) __CFRunLoop * CFRunLoopRef;
struct __CFRunLoop {
    ...
    pthread_t _pthread;
    uint32_t _winthread;
    CFMutableSetRef _commonModes;
    CFMutableSetRef _commonModeItems;
    CFRunLoopModeRef _currentMode;
    CFMutableSetRef _modes;//集合包含各种CFRunLoopModeRef对象
    ...
};

CFRunLoopModeRef底层结构

struct __CFRunLoopMode {
    ...
    CFStringRef _name;
    CFMutableSetRef _sources0;//(集合包含CFRunLoopSourceRef)
    CFMutableSetRef _sources1;
    CFMutableArrayRef _observers;//数组包含CFRunLoopObserverRef
    CFMutableArrayRef _timers;//数组包含CFRunLoopTimeRef
    ...
};

CFRunLoopModeRef

常见2种mode

  • kCFRunLoopDefaultModel(NSDefaultRunLoopMode),App默认mode,通常主线程处于这个mode下.
  • UITrackingRunLoopMode:界面跟踪Mode,用于ScrollView追踪滑动触摸,保证界面滑动时候不受其他mode影响.

source0

  • 触摸事件处理
  • performSelectoreThread

source1

  • 基于port的线程间通信
  • 系统事件捕捉

timers

  • NSTimer
  • performSelector: withObject: afterDelay:

observers

  • 监听runloop状态
  • UI刷新

CFRunLoopObserverRef

有几种模式

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    NSRunLoop *runloop;
    CFRunLoopRef runloop2;
    
    runloop = [NSRunLoop currentRunLoop];
    runloop2 = CFRunLoopGetCurrent();
    
    
    CFRunLoopObserverRef observer = CFRunLoopObserverCreate(kCFAllocatorDefault, kCFRunLoopAllActivities, YES, 0, MyCFRunLoopObserverCallBack, NULL);
    CFRunLoopAddObserver(runloop2, observer, kCFRunLoopCommonModes);
    CFRelease(observer);
    
}

/*
 
 kCFRunLoopEntry = (1UL << 0),
 kCFRunLoopBeforeTimers = (1UL << 1),
 kCFRunLoopBeforeSources = (1UL << 2),
 kCFRunLoopBeforeWaiting = (1UL << 5),
 kCFRunLoopAfterWaiting = (1UL << 6),
 kCFRunLoopExit = (1UL << 7),
 kCFRunLoopAllActivities = 0x0FFFFFFFU
 
 */
void MyCFRunLoopObserverCallBack(CFRunLoopObserverRef observer,
                               CFRunLoopActivity activity,
                               void *info)
{
    switch (activity) {
        case kCFRunLoopEntry:
            NSLog(@"kCFRunLoopEntry");
            break;
//        case kCFRunLoopBeforeTimers:
//            NSLog(@"kCFRunLoopBeforeTimers");
//            break;
//        case kCFRunLoopBeforeSources:
//            NSLog(@"kCFRunLoopBeforeSources");
//            break;
//        case kCFRunLoopBeforeWaiting:
//            NSLog(@"kCFRunLoopBeforeWaiting");
//            break;
//        case kCFRunLoopAfterWaiting:
//            NSLog(@"kCFRunLoopAfterWaiting");
//            break;
        case kCFRunLoopExit:
            NSLog(@"kCFRunLoopExit");
            break;
            
        default:
            break;
    }
    
}

  • CFRunLoopModeRef代表RunLoop的运行模式.
  • 一个RunLoop包含若干个Mode,每个Mode又包含若干个/sources0/sources1/observers/timers.
  • RunLoop启动时候只能选择一个mode,作为currentMode.
  • 切换Mode,只能退出当前Loop,再重新选择mode.

流程图

实际应用

  • 控制线程声明周期(线程保活)
  • 解决NSTimer在滑动时候停止工作
  • 监控应用卡顿
  • 性能优化

线程保活

@interface ViewController ()

@property (nonatomic,strong) MyThread *thread;
@property (nonatomic,assign) BOOL isStop;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    [self.thread start];

}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
    if (self.isStop) {
        return;
    }
    [self performSelector:@selector(test) onThread:self.thread withObject:nil waitUntilDone:YES];
}

- (void)test{
    NSLog(@"test");
    
}

- (IBAction)stopXib:(id)sender {
    if (self.isStop) {
        return;
    }
    [self performSelector:@selector(stopThread) onThread:self.thread withObject:nil waitUntilDone:YES];
}

- (void)stopThread{
    self.isStop = YES;
    CFRunLoopStop(CFRunLoopGetCurrent());
}

- (MyThread *)thread{
    if (!_thread) {
        __weak typeof(self) weakSelf = self;
        _thread = [[MyThread alloc]initWithBlock:^{
            NSLog(@"---begin----%@",[NSThread currentThread]);
            
            [[NSRunLoop currentRunLoop]addPort:[NSPort new] forMode:NSDefaultRunLoopMode];
//            [[NSRunLoop currentRunLoop]run];
            while (weakSelf && !weakSelf.isStop) {
                [[NSRunLoop currentRunLoop]runMode:NSDefaultRunLoopMode beforeDate: [NSDate distantFuture]];
            }
            
            NSLog(@"---end----%@",[NSThread currentThread]);
            
        }];
    }
    return _thread;
}

- (void)viewWillDisappear:(BOOL)animated{
    [super viewWillDisappear:animated];
    
}

- (void)dealloc{
    NSLog(@"%s",__func__);
    [self stopXib:nil];
    
}

接口封装
.h

typedef void(^MyTaskBlock)(void);
@interface MyPermenantThread : NSObject

- (void)run;

- (void)executeTask:(MyTaskBlock)block;

- (void)stop;

@end

.m

@interface MyPermenantThread()

@property (nonatomic,strong) MyThread *innerThread;
@property (nonatomic,assign,getter=isStopped) BOOL stopped;
@end

@implementation MyPermenantThread

- (instancetype)init
{
    self = [super init];
    if (self) {
        __weak typeof (self) weakSelf = self;
        self.innerThread = [[MyThread alloc]initWithBlock:^{
           
            [[NSRunLoop currentRunLoop]addPort:[NSPort new] forMode:NSDefaultRunLoopMode];
            
            while (weakSelf && !weakSelf.isStopped) {
                [[NSRunLoop currentRunLoop]runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
            };
            
        }];
        
    }
    return self;
}


- (void)run{
    if (!self.innerThread) {
        return;
    }
    [self.innerThread start];
}

- (void)executeTask:(MyTaskBlock)block{
    if (!self.innerThread || !block) {
        return;
    }
    [self performSelector:@selector(__executeTask:) onThread:self.innerThread withObject:block waitUntilDone:NO];
}

- (void)stop{
    if (!self.innerThread) {
        return;
    }
    [self performSelector:@selector(__stop) onThread:self.innerThread withObject:nil waitUntilDone:YES];
}

- (void)dealloc{
    [self stop];
}

#pragma mark -- private methods
- (void)__stop{
    self.stopped = YES;
    CFRunLoopStop(CFRunLoopGetCurrent());
    self.innerThread = nil;
}

- (void)__executeTask:(MyTaskBlock)block
{
    block();
}

@end

c语言实现

            NSLog(@"begin");
            
            CFRunLoopSourceContext context = {0} ;
            
            CFRunLoopSourceRef source = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context);
            
            CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
            
             while (weakSelf && !weakSelf.isStopped) {
                 //第三个参数 执行完退出YES.
                 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1.0e10, true);
            }
            
            CFRelease(source);
            
            NSLog(@"end");

你可能感兴趣的:(RunLoop)