iOS RunLoop简单理解与运用

2017-04-24  本文已影响50人  大大盆子

二话不说先上我麦来压压惊


什么是RunLoop?

RunLoop顾名思义运行着的循环,而且是一个死循环,他负责监听几乎所有的事件(触摸事件,网络事件,时钟事件),当监听到了事件就会唤醒线程去执行,没事件线程就睡觉。

RunLoop常见的模式

RunLoop在同一时间中只能响应一种模式下的事件,同时会关闭上一种模式;不同的事件都有对应的模式,处理事件都会切换到事件对应的模式。
<ul>
<li> NSDefalutRunLoopMode //默认模式
<li> UITrackingRunLoopMode //拖动事件,例如:UIScrollView
<li> NSRunLoopCommonModes //占位模式,包含前面两个

RunLoop跟线程的关系

RunLoop优化

RunLoop如何优化?我们都知道耗时操作放到子线程中执行,更新UI放到主线程执行(在子线程中更新UI也会等到子线程所有操作执行完了然后再到主线程中执行UI操作,因为UIKit是线程不安全的:UI控件都是用的原子属性->效率高。),那么如果更新UI耗时长怎么办?其实是因为RunLoop在一次循环当中执行了过多的复杂的UI操作,我们需要对UI操作做拆分,然后增加RunLoop的循环次数来分步执行,一次循环只做一个UI更新模块,从而保证RunLoop的流畅性。

- (void)addRunLoopObserver{
    
    //添加RunLoop监听,需要使用CFRunLoop,因为NSRunloop没有这个功能
    
    //1.获取runloop
    CFRunLoopRef runLoop = CFRunLoopGetCurrent();
    
    //2.1创建上下文
    CFRunLoopObserverContext context = {
        
        0, //这个context的版本
        (__bridge void *)(self), //传入的参数,这里我传入控制器
        CFRetain, //告诉它retain是调用哪个函数
        CFRelease, //告诉它release是调用哪个函数
        nil,
    };
    
    //2.2创建runloop观察者
    /*
     CFRunLoopObserverRef CFRunLoopObserverCreate(CFAllocatorRef allocator,
                                                 CFOptionFlags activities,
                                                 Boolean repeats,
                                                 CFIndex order,
                                                 CFRunLoopObserverCallBack callout,
                                                 CFRunLoopObserverContext *context);
     
     @param allocator:这个参数用来分配空间给新的对象。默认情况下使用NULL或者kCFAllocatorDefault。
     @param activities:设置Runloop的运行阶段的标志,当运行到此阶段时,CFRunLoopObserver会被调用
     @param repeats:CFRunLoopObserver是否循环调用,false为单词调用,否则循环调用。
     @param order:CFRunLoopObserver的优先级,当在Runloop同一运行阶段中有多个CFRunLoopObserver时,根据这个来先后调用CFRunLoopObserver。正常情况下使用0。
     @param callout:回调函数
     @param context:CFRunLoopObserver结构体里面的一个结构体,它主要用来给回调函数传递消息的。
     @return CFRunLoopObserverRef:观察者指针对象
     */
    CFRunLoopObserverRef observer = CFRunLoopObserverCreate(NULL,
                                                            kCFRunLoopBeforeWaiting,
                                                            YES, 0,
                                                            callBack,
                                                            &context);
    
    //3.给runloop添加观察者
    CFRunLoopAddObserver(runLoop, observer, kCFRunLoopCommonModes);
    
    
    //4.通过定时器来增加runloop循环次数
    [NSTimer scheduledTimerWithTimeInterval:0.001
                                     target:self
                                   selector:@selector(timerAction)
                                   userInfo:nil
                                    repeats:YES];
}

- (void)timerAction{
    //不执行任何代码,只作为一个触发runloop监听回调的功能。
}

/**
 回调函数,在kCFRunLoopBeforeWaiting(runloop等待执行循环之前)情况下调用,因为定时器给的是0.001秒,所以这里调用非常频繁,保证一次循环执行一个任务

 @param observer 观察者对象
 @param activity Runloop的运行阶段的标志
 @param info CFRunLoopObserverContext传入的参数
 */
void callBack(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info){
    
    //1.拿到传过来的参数,再进行转换,因为这是C函数,不能直接调用self,所以在添加观察的时候把self传过来。
    ViewController *vc = (__bridge ViewController *)(info);
    
    //2.执行拆分之后的UI模块(拆分的模块用task数组装起来,具体任务包装在block中,在这里只要执行block即可)
    if (vc.tasks.count == 0) {
        return;
    }
    RunLoopBlock block = vc.tasks.firstObject;
    !block?:block();
    [vc.tasks removeObjectAtIndex:0];
}
    
上一篇 下一篇

猜你喜欢

热点阅读