乐趣区

iOS-涨薪-Run-Loop-面试题

Run Loop

运行循环

app 程序只有不停地运行, 能力一直响应用户的操作

Run Loop 两大性能:


  • 睡眠中,期待音讯
  • 解决音讯

从睡眠中 -> 解决音讯, 须要一个唤醒的过程


1、讲讲 RunLoop, 我的项目中有用到吗?

RunLoop 的根本作用:

放弃程序的继续运行

节俭 CPU 的资源,进步程序的性能(没有事件,就请休眠,不要功耗。有事件,就解决)


2、RunLoop 外部实现逻辑?

  • Core Foundation 中对于 RunLoop 的 5 个类:

CFRunLoopRef

CFRunLoopModeRef

CFRunLoopSourceRef

CFRunLoopTimerRef

CFRunLoopObserverRef

  • __CFRunLoop 的数据结构
struct __CFRunLoop {
    CFRuntimeBase _base;
    pthread_mutex_t _lock;            /* locked for accessing mode list */
    __CFPort _wakeUpPort;            // used for CFRunLoopWakeUp 
    Boolean _unused;
    volatile _per_run_data *_perRunData;              // reset for runs of the run loop
    
    
    
    pthread_t _pthread;
    uint32_t _winthread;
    
    
    
    CFMutableSetRef _commonModes;
    CFMutableSetRef _commonModeItems;
    CFRunLoopModeRef _currentMode;
    

    // 这里有一个汇合

    CFMutableSetRef _modes;
    
    
    
    struct _block_item *_blocks_head;
    struct _block_item *_blocks_tail;
    CFAbsoluteTime _runTime;
    CFAbsoluteTime _sleepTime;
    CFTypeRef _counterpart;
};

3、RunLoop 和线程的关系?

  • 每条线程,都有惟一的一个,与之对应的 RunLoop 对象

runloops[thread] = runloop

  • RunLoop 保留在一个全局的 Dictionary 里,线程作为 Key, RunLoop 作为 Value
  • 线程刚创立时,并没有 RunLoop 对象,RunLoop 会在第一次获取它时,创立
  • RunLoop 会在线程完结时,销毁

线程都没有了,runloop 也就没有意义了

子线程,要什么 runloop?

没有 runloop , 就是命令行,调用一次就完结

有了 runloop, 能够重复休眠、唤醒、解决音讯


  • 主线程的 RunLoop 曾经主动获取(创立),子线程默认没有开启 RunLoop

子线程中,获取一下 currentRunLoop, 就创立开启了 RunLoop

CFRunLoopRef CFRunLoopGetCurrent(void) {CHECK_FOR_FORK();
    CFRunLoopRef rl = (CFRunLoopRef)_CFGetTSD(__CFTSDKeyRunLoop);
    if (rl) return rl;
    
    // 从这里拿
    return _CFRunLoopGet0(pthread_self());
}

进入详情

// should only be called by Foundation
// t==0 is a synonym for "main thread" that always works
CF_EXPORT CFRunLoopRef _CFRunLoopGet0(pthread_t t) {if (pthread_equal(t, kNilPthreadT)) {t = pthread_main_thread_np();
    }
    __CFLock(&loopsLock);
    if (!__CFRunLoops) {__CFUnlock(&loopsLock);
    CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks);
    CFRunLoopRef mainLoop = __CFRunLoopCreate(pthread_main_thread_np());
    CFDictionarySetValue(dict, pthreadPointer(pthread_main_thread_np()), mainLoop);
    if (!OSAtomicCompareAndSwapPtrBarrier(NULL, dict, (void * volatile *)&__CFRunLoops)) {CFRelease(dict);
    }
    CFRelease(mainLoop);
        __CFLock(&loopsLock);
    }
    CFRunLoopRef loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));
    __CFUnlock(&loopsLock);
    if (!loop) {CFRunLoopRef newLoop = __CFRunLoopCreate(t);
        __CFLock(&loopsLock);
        
        
     // 从字典外面,获取 runloop 对象
    // __CFRunLoops 字典
    // pthreadPointer(t),键 key
    
    
    loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));
    
    // runloop 对象 loop 不存在,就新建
    if (!loop) {
            // 字典中,设置
            //   __CFRunLoops  字典
            //   pthreadPointer(t),键 key
            //   newLoop,值  value
        CFDictionarySetValue(__CFRunLoops, pthreadPointer(t), newLoop);
        loop = newLoop;
    }
        // don't release run loops inside the loopsLock, because CFRunLoopDeallocate may end up taking it
        __CFUnlock(&loopsLock);
    CFRelease(newLoop);
    }
    if (pthread_equal(t, pthread_self())) {_CFSetTSD(__CFTSDKeyRunLoop, (void *)loop, NULL);
        if (0 == _CFGetTSD(__CFTSDKeyRunLoopCntr)) {_CFSetTSD(__CFTSDKeyRunLoopCntr, (void *)(PTHREAD_DESTRUCTOR_ITERATIONS-1), (void (*)(void *))__CFFinalizeRunLoop);
        }
    }
    return loop;
}


4、timer 和 runloop 的关系?

5、程序中增加每 3 秒响应一次的 NSTimer, 当拖动 tableView 时 timer 可能无奈响应,要怎么解决?

6、RunLoop 是怎么响应用户操作的,具体流程是什么样的?


7、说说 RunLoop 的几种状态

8、runloop 的 mode 作用是什么?


应用的代码,目前最新 1153

退出移动版