iOS原理(七)----runloop

iOS原理(七)----runloop

runloop:顾名思义,运行循环,在程序运行过程中循环做一些事情,保持程序的持续运行,处理App中的各种事件(比如触摸事件、定时器事件等),节省CPU资源,提高程序性能:该做事时做事,该休息时休息.包括定时器(Timer),PerformSelector, GCD Async Main Queue,事件响应、手势识别、界面刷新,网络请求, AutoreleasePool.

  • 每条线程都有唯一的一个与之对应的RunLoop对象
  • RunLoop保存在一个全局的Dictionary里,线程作为key,RunLoop作为value
  • 线程刚创建时并没有RunLoop对象,RunLoop会在第一次获取它时创建
  • RunLoop会在线程结束时销毁
  • 主线程的RunLoop已经自动获取(创建),子线程默认没有开启RunLoop

RunLoop的五个类: CFRunLoopRef, CFRunLoopModeRef, CFRunLoopSourceRef, CFRunLoopTimerRef, CFRunLoopObserverRef.

其中CFRunloop结构如下:

struct __CFRunLoop {
    CFRuntimeBase _base;
    pthread_mutex_t _lock;
    __CFPort _wakeUpPort;
    Boolean _unused;
    volatile _per_run_data *_perRunData;
    pthread_t _pthread; // 线程
    uint32_t _winthread;
    CFMutableSetRef _commonModes; // 共用模式
    CFMutableSetRef _commonModeItems; // 共用items
    CFRunLoopModeRef _currentMode; // 当前模式
    CFMutableSetRef _modes; // 所有的模式
    struct _block_item *_blocks_head;
    struct _block_item *_blocks_tail;
    CFAbsoluteTime _runTime;
    CFAbsoluteTime _sleepTime;
    CFTypeRef _counterpart;
};

CFRunLoopMode结构如下:

struct __CFRunLoopMode {
    CFRuntimeBase _base;
    pthread_mutex_t _lock;
    CFStringRef _name;
    Boolean _stopped;
    char _padding[3];
    CFMutableSetRef _sources0;
    CFMutableSetRef _sources1;
    CFMutableArrayRef _observers;
    CFMutableArrayRef _timers;
    CFMutableDictionaryRef _portToV1SourceMap;
    __CFPortSet _portSet;
    CFIndex _observerMask;
    uint64_t _timerSoftDeadline;
    uint64_t _timerHardDeadline; 
};
  • CFRunLoopModeRef代表RunLoop的运行模式
  • 一个RunLoop包含若干个Mode,每个Mode又包含若干个Source0/Source1/Timer/Observer
  • RunLoop启动时只能选择其中一个Mode,作为currentMode
  • 如果需要切换Mode,只能退出当前Loop,再重新选择一个Mode进入,不同组的Source0/Source1/Timer/Observer能分隔开来,互不影响
  • 如果Mode里没有任何Source0/Source1/Timer/Observer,RunLoop会立马退出

其中有两种常用的Mode:

  • kCFRunLoopDefaultMode(NSDefaultRunLoopMode):App的默认Mode,通常主线程是在这个Mode下运行
  • UITrackingRunLoopMode:界面跟踪 Mode,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响

RunLoop的运行流程:

  • Source0:触摸事件处理, performSelector:onThread:.
  • Source1:基于Port的线程间通信,系统事件捕捉.
  • Timers: NSTimer,performSelector:withObject:afterDelay:
  • Observers:用于监听RunLoop的状态, UI刷新(BeforeWaiting), Autorelease pool(BeforeWaiting).

01、通知Observers:进入Loop

02、通知Observers:即将处理Timers

03、通知Observers:即将处理Sources

04、处理Blocks

05、处理Source0(可能会再次处理Blocks)

06、如果存在Source1,就跳转到第8步

07、通知Observers:开始休眠(等待消息唤醒)

08、通知Observers:结束休眠(被某个消息唤醒)

01> 处理Timer

02> 处理GCD Async To Main Queue

03> 处理Source1

09、处理Blocks

10、根据前面的执行结果,决定如何操作

01> 回到第02步

02> 退出Loop

11、通知Observers:退出Loop

RunLoop的应用:

  • 控制线程生命周期(线程保活,通常我们频繁需要子线程处理事情,让线程不要重复创建)
  • 解决NSTimer在滑动时停止工作的问题
  • 监控应用卡顿
  • 性能优化

你可能感兴趣的:(iOS原理(七)----runloop)