【iOS】RunLoop

前言-什么是RunLoop?

什么是RunLoop? 跑圈?字面上理解确实是这样的。

Apple官方文档这样解释RunLoop

RunLoop是与线程息息相关的基本结构的一部分。RunLoop是一个调度任务和处理任务的事件循环。RunLoop的目的是为了在有工作的时候让线程忙起来,而在没有工作的时候让线程进入休眠状态。

之所以iOS的app能够持续的响应从而让程序保持运行状态,在于其存在一个事件循环(Event Loop)机制: 线程能够随时响应并处理事件的机制,这种机制要求线程不能退出从而高效的完成事件调度和处理。

在iOS这种事件循环机制就叫做RunLoop

RunLoop实际上是一个对象,对象在循环中处理程序运行过程出现的各种事件(比如触摸事件,UI刷新事件,定时器事件,Selector事件)从而保持程序的持续运行并且让程序在没有事件处理的时候进入休眠状态,从而节省CPU资源达到提升程序性能的目的。

默认情况下主线程的RunLoop原理

#import <UIKit/UIKit.h>
#import "AppDelegate.h"

int main(int argc, char * argv[]) {
   
    NSString * appDelegateClassName;
    @autoreleasepool {
   
        // Setup code that might create autoreleased objects goes here.
        appDelegateClassName = NSStringFromClass([AppDelegate class]);
    }
    return UIApplicationMain(argc, argv, nil, appDelegateClassName);
}

return UIApplicationMain(argc, argv, nil, appDelegateClassName);这是 iOS 应用程序的主运行循环,它负责处理用户事件、界面更新和应用程序的主要逻辑。UIApplicationMain 函数创建应用程序对象和主运行循环,并传递控制权给应用程序的委托类(AppDelegate)来处理应用程序的逻辑。

其中的UIApplicationMain函数内部帮我们开启了主线程的RunLoop
UIApplicationMain内部拥有一个无限循环的代码。

function loop() {
   
    initialize();
    do {
   
        var message = get_next_message();
        process_message(message);
    } while (message != quit);
}

程序会一直在do-while循环中执行。

Apple官方的RunLoop模型图

在这里插入图片描述

RunLoop就是线程中的一个循环,RunLoop在循环中不断检测,通过Input sources(输入源)和Timer sources(定时源)两种来源等待接受消息,然后对接收到的事件通知线程进行处理,并在没有事件的时候进行休息。

1. RunLoop对象

RunLoop对象是基于CFFoundation框架的CFRunLoopRef类型封装的对象。

  • NSRunLoop是基于CFRunLoopRef的封装,提供了面向对象的API,但是这些API不是线程安全的。
[NSRunLoop currentRunLoop];//获得当前RunLoop对象
[NSRunLoop mainRunLoop];//获得主线程的RunLoop对象

CoreFoundation框架的 CFRunLoopRef对象

  • CFRunLoopRef是在CoreFoundation框架内的,其提供了纯C语言函数的API,所有这些API都是线程安全的。
CFRunLoopGetCurrent();//获得当前线程的RunLoop对象
CFRunLoopGetMain();//获得主线程的RunLoop对象

在这里插入图片描述

那么对应的两种方式就是:

- (void)getRunLoop {
   
    NSRunLoop *runloop  = [ NSRunLoop currentRunLoop];
    NSRunLoop *manRlp = [NSRunLoop mainRunLoop];
    
    CFRunLoopRef cfRlp = CFRunLoopGetCurrent();
    CFRunLoopRef mainCfRlp = CFRunLoopGetMain();
}

看下CFRunLoopGetCurrentCFRunLoopGetMain的具体实现:

CFRunLoopRef CFRunLoopGetCurrent(void) {
   
    CHECK_FOR_FORK();
    CFRunLoopRef rl = (CFRunLoopRef)_CFGetTSD(__CFTSDKeyRunLoop);
    if (rl) return rl;
    return _CFRunLoopGet0(pthread_self());
}

CFRunLoopRef CFRunLoopGetMain(void) {
   
    CHECK_FOR_FORK();
    static CFRunLoopRef __main = NULL; // no retain needed
    if (!__main) __main = _CFRunLoopGet0(pthread_main_thread_np()); // no CAS needed
    return __main;
}

发现在过程都调用了_CFRunLoopGet0这个函数,后面再进行讲解。

CFRunLoopRef源码部分(引入线程相关)

CFRunLoopRef的源码部分

struct __CFRunLoop {
   
    CFRuntimeBase _base;
    pthread_mutex_t _lock;            /* locked for accessing mode list */
    __CFPort _wakeUpPort; //【通过该函数CFRunLoopWakeUp内核向该端口发送消息可以唤醒runloop】
    Boolean _unused;
    volatile _per_run_data *_perRunData;              // reset for runs of the run loop
    pthread_t _pthread; //【RunLoop对应的线程】
    uint32_t _winthread;
    CFMutableSetRef _commonModes; // 【存储的是字符串,记录所有标记为common的mode】
    CFMutableSetRef _commonModeItems;//【存储所有commonMode的item(source、timer、observer)】
    CFRunLoopModeRef _currentMode;//【当前运行的mode】
    CFMutableSetRef _modes;//【存储的是CFRunLoopModeRef】
    struct _block_item *_blocks_head;//【do blocks时用到】
    struct _block_item *_blocks_tail;
    CFTypeRef _counterpart;
};

对于一些属性之外,重点需要关注三个成员变量

pthread_t _pthread;【RunLoop对应的线程】
CFRunLoopModeRef _currentMode;【当前运行的mode】
CFMutableSetRef _modes;【存储的是CFRunLoopModeRef】

看看RunLoop和线程的关系。

2. RunLoop和线程

先看一下_CFRunLoopGet0这个函数是怎么实现的,和RunLoop和线程有什么关系。

//全局的Dictionary,key是pthread_t,value是CFRunLoopRef
static CFMutableDictionaryRef __CFRunLoops = NULL;
//访问__CFRunLoops的锁
static CFSpinLock_t loopsLock = CFSpinLockInit;

// should only be called by Foundation
// t==0 is a synonym for "main thread" that always works
//t==0是始终有效的“主线程”的同义词

//获取pthread对应的RunLoop
CF_EXPORT CFRunLoopRef _CFRunLoopGet0(pthread_t t) {
   
    if (pthread_equal(t, kNilPthreadT
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值