ios runloop总结

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ios runloop总结相关的知识,希望对你有一定的参考价值。

参考技术A 面试回答方式:

通常来讲,一个线程在执行完任务后,会直接退出。 但在我们日常的App使用中,即使什么都不做,App也不会退出。这其中的原理,便是在线程中构建一个消息循环,使得这个线程中一直有任务执行。在ios和OSX中,这个消息循环的机制便被称为RunLoop。

RunLoop 可以保持程序的持续运行,它负责处理事件和消息,可以让线程在没有消息的时候休眠,在有消息的时候才唤醒做事, 以节省CPU资源。

iOS系统中,提供了2套API来访问和使用RunLoop。

CoreFoundation框架中的CFRunLoopRef对象,它提供了纯C函数的API,是线程安全的。苹果开源了CFRunLoopRef

Foundation框架中的NSRunLoop对象,它是基于CFRunLoopRef的封装,但是这些API不是线程安全的

其实我们在使用runloop的时候大多可以使用CFRunLoopRef进行操作

一、runloop和线程有什么关系呢?

我们需要看一下runloop,主线程会始终维护一个runloop,那么子线程呢,由于苹果是不允许直接创建runloop的,所以runloop的获取提供了两个方式CFRunLoopGetMain() 和 CFRunLoopGetCurrent(),而这两个函数的内部实现是先为主线程创建一个runloop,子线程的话是通过传入的key来获取一个runloop,没有获取到则创建一个,所以子线程如果不获取runloop则子线程便不存在runloop

所以:

1.线程和 RunLoop 之间是一一对应的,其关系是保存在一个全局的 Dictionary 里。

2.子线程刚创建时并没有RunLoop,如果你不主动获取,那它一直都不会有。

3.RunLoop 会在第一次获取时创建,在线程结束时销毁。

4.主线程的RunLoop已经自动获取(创建),子线程默认没有开启RunLoop

二、runloop的结构

关于runloop有五个类,分别是

CFRunLoopRef

CFRunLoopModeRef

CFRunLoopSourceRef

CFRunLoopObserverRef

CFRunLoopTimerRef

而这几个类内部结构都是一个结构体,在每一个而结构体中都有一个    pthread_t _pthread;属性则可以看出  runloop和线程是一一对应关系,每个runloop内部会保留一个对应的线程

其中 CFRunLoopModeRef 的结构体如下

struct __CFRunLoopMode

    CFStringRef _name;

    CFMutableSetRef _sources0;

    CFMutableSetRef _sources1;

    CFMutableArrayRef _observers;

    CFMutableArrayRef _timers;

;

其中

CFRunLoopSourceRef是事件的触发器

CFRunLoopModeRef是当前的runloop的mode选择,苹果公开提供的Mode有两个:kCFRunLoopDefaultMode(NSDefaultRunLoopMode)和UITrackingRunLoopMode

CFRunLoopTimerRef是基于时间的触发器

CFRunLoopObserverRef是事件变化的观察者

说道这里即可————————

runloop的实际应用场景:

1.如事件的监听

比如IM中消息的长按应该出现复制,转发等弹框操作,但是对消息Label本身区域进行长按水平滑动又需要出现放大镜弹框显示放大文字,这种不同事件的响应可以采用CFRunLoopObserverRef来进行判断

如:

currentMode = CFRunLoopCopyCurrentMode(CFRunLoopGetMain());

     //设置手势

        [self setupGestures];

        __weak __typeof(self)weakSelf = self;

        CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(kCFAllocatorDefault,kCFRunLoopAllActivities,YES,0,^(CFRunLoopObserverRef observer,CFRunLoopActivity activity)

            __strong __typeof(weakSelf)strongSelf = weakSelf;

            if(strongSelf==nil)

                return;

           

            CFComparisonResult rest = CFStringCompare(strongSelf->currentMode,CFRunLoopCopyCurrentMode(CFRunLoopGetMain()),kCFCompareBackwards);

            if(rest != kCFCompareEqualTo)

                strongSelf->currentMode = CFRunLoopCopyCurrentMode(CFRunLoopGetMain());

                if((NSString *)CFBridgingRelease(strongSelf->currentMode)== UITrackingRunLoopMode)

                   //正在长按横向滑动/拖拽

                  [strongSelf scrollDidScroll];

               

           

        );

        CFRunLoopAddObserver(CFRunLoopGetMain(),observer,kCFRunLoopCommonModes);

2.定时器的使用

3.创建一个常驻线程

说白了就是一直跑一个NSRunloop让线程保活,不用时候休眠(这也是性能优化的一个点喔!)

比如我有一个for循环,循环内部又有一个在主线程很耗时的操作,此时我想开一个子线程来处理耗时,但是循环一次,线程就开辟一次,不断的开辟线程去性能是十分损耗的,但是上述说过,子线程不主动获取runloop是不存在的,所以此时我们可以让runloop一直对线程保活。

引申,其实这里单独开一个小的线程去执行某个action的话可以使用NSThread的

4.发现和消除卡顿

5.app 异常捕捉

附:

runloop内部底层实现可以参考上述文章链接进行更深的讲解

如:RunLoop 的核心是基于 mach port 的,其进入休眠时调用的函数是 mach_msg()其实这里就是更底层之间的消息传递

以上是关于ios runloop总结的主要内容,如果未能解决你的问题,请参考以下文章

iOS总结篇-RunLoop

iOS 多线程:『RunLoop』详尽总结

RunLoop总结:RunLoop的应用场景

RunLoop 总结:RunLoop的应用场景

RunLoop相关知识的总结

RunLoop总结:RunLoop基础知识