RunLoop

作者: comsubin | 来源:发表于2019-06-10 14:08 被阅读0次

    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<UITouch *> *)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

          本文链接:https://www.haomeiwen.com/subject/gzxsxctx.html