Run Loop面试题

  1. 什么是Run Loop?
    • 从字面上看:运行循环、跑圈。

    • 它的内部是do-while循环,在这个循环内部不断处理各种任务。(Source、Timer、Observer)

    • 一个线程对应一个Run Loop,主线程的Run Loop默认启动。子线程的Run Loop需要手动启动,调用run方法。

      //CFRunLoop.c
      //创建主线程Run Loop
      CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks);
      
    CFRunLoopRef mainLoop = __CFRunLoopCreate(pthread_main_thread_np());
    CFDictionarySetValue(dict, pthreadPointer(pthread_main_thread_np()), mainLoop);
    //子线程Run Loop的创建
    if (!loop) {
    CFDictionarySetValue(__CFRunLoops, pthreadPointer(t), newLoop);
    loop = newLoop;
    }
    //新线程做Key,newLoop为Value,所以线程与Run Loop一一对应。
    ```
    • Run Loop只能选择一个Model启动,如果当前Model中没有任何Source(Source0,Source0)、Timer、就会退出Run Loop。(注意:即使有Observer也会退出Run Loop,Source、Timer主动给Run Loop发消息,Observer被动接收消息)

      //CFRunLoop.c
      static Boolean __CFRunLoopModeIsEmpty(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopModeRef previousMode) {
      
    CHECK_FOR_FORK();
    if (NULL == rlm) return true;

if DEPLOYMENT_TARGET_WINDOWS

if (0 != rlm->_msgQMask) return false;

endif

Boolean libdispatchQSafe = pthread_main_np() && ((HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY && NULL == previousMode) || (!HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY && 0 == _CFGetTSD(__CFTSDKeyIsInGCDMainQ)));
if (libdispatchQSafe && (CFRunLoopGetMain() == rl) && CFSetContainsValue(rl->_commonModes, rlm->_name)) return false; // represents the libdispatch main queue
//判断sources0、sources1、timers,没有判断Observer
if (NULL != rlm->_sources0 && 0 < CFSetGetCount(rlm->_sources0)) return false;
if (NULL != rlm->_sources1 && 0 < CFSetGetCount(rlm->_sources1)) return false;
if (NULL != rlm->_timers && 0 < CFArrayGetCount(rlm->_timers)) return false;
struct _block_item *item = rl->_blocks_head;
while (item) {
    struct _block_item *curr = item;
    item = item->_next;
    Boolean doit = false;
    if (CFStringGetTypeID() == CFGetTypeID(curr->_mode)) {
        doit = CFEqual(curr->_mode, rlm->_name) || (CFEqual(curr->_mode, kCFRunLoopCommonModes) && CFSetContainsValue(rl->_commonModes, rlm->_name));
    } else {
        doit = CFSetContainsValue((CFSetRef)curr->_mode, rlm->_name) || (CFSetContainsValue((CFSetRef)curr->_mode, kCFRunLoopCommonModes) && CFSetContainsValue(rl->_commonModes, rlm->_name));
    }
    if (doit) return false;
}
return true;

}

    ```
  1. 开发中Run Loop的使用场景:
    • 开启一个常驻线程。(让一个子线程不进入消亡状态,等待其他线程发来消息,处理其它事件)
      • 在子线程中开启一个定时器。
      • 在子线程中进行长期监控。(监控网络状态)
    • 可以让定时器在特定模式下执行。
    • 可以让某些事件(行为、任务)在特定模式下执行。
    • 可以添加Observer监听Run Loop状态,比如监听点击事件的处理。(在所有点击事件之前做一些事情)
  2. 自动释放池什么时候释放?
    • 通过Observer监听Run Loop的状态,一旦监听到Run Loop即将进入睡眠状态,就释放自动释放池。(kCFRun LoopBeforeWaiting)

你可能感兴趣的:(Run Loop面试题)