首页 > 其他分享 >iOS开发基础122-RunLoop

iOS开发基础122-RunLoop

时间:2024-07-17 16:59:56浏览次数:9  
标签:__ 定时器 iOS currentMode 122 rl RunLoop mach

深入探讨 RunLoop 的底层实现需要了解 Core Foundation 框架中的 CFRunLoop 以及与 RunLoop 工作机制紧密相关的操作系统底层 API。这些底层实现主要涉及到事件源、定时器和线程的调度机制。本文将深入剖析 RunLoop 的底层结构及其运行流程。

一、RunLoop 底层数据结构

涉及 RunLoop 的核心数据结构主要包括:

  1. CFRunLoopRef :表示一个 RunLoop 对象。
  2. CFRunLoopModeRef :表示 RunLoop 的运行模式。每个 RunLoop 可以有多个模式,但同一时刻只能使用一个模式。
  3. CFRunLoopSourceRef :表示输入源,用于处理异步事件。
  4. CFRunLoopTimerRef :表示定时器事件。
  5. CFRunLoopObserverRef :观察者,用于监听 RunLoop 的状态变化。

每个 RunLoop 都维护一个输入源列表、定时器列表和观察者列表,并按模式分组管理。

二、RunLoop 的核心组件和工作机制

1. CFRunLoopMode

RunLoop 有五种预定义模式:

  • kCFRunLoopDefaultMode :默认模式,通常 UI 操作、定时器等在这个模式下运行。
  • UITrackingRunLoopMode :用于检测用户 UI 交互的模式,如滚动等。
  • kCFRunLoopCommonModes :一个伪类别的模式,被标记为公共模式的事件源会应用于所有的公共模式。
  • GSEventReceiveRunLoopMode :基础设施的一部分,用于接收系统事件。
  • kCFRunLoopDefaultMode :具体用于 CA。

每个 CFRunLoopMode 包含以下内容:

  • Sources0 :不自动触发的输入源。
  • Sources1 :基于端口的输入源。
  • Timers :定时器。
  • Observers :状态观察者。

2. CFRunLoopSource

CFRunLoopSource 分为两类:

  • Source0 :手动触发,由应用负责管理。
  • Source1 :基于内核机制(如端口、Socket等)的输入源,自动触发。

3. CFRunLoopTimer

定时器事件,基于时间的触发机制。CFRunLoopTimer 会在设置的时间间隔后被触发,并且可以配置为重复或单次触发。

4. CFRunLoopObserver

用于监控 RunLoop 的状态变化,包含以下几种状态:

  • kCFRunLoopEntry :进入 RunLoop
  • kCFRunLoopBeforeTimers :准备处理定时器。
  • kCFRunLoopBeforeSources :准备处理输入源。
  • kCFRunLoopBeforeWaiting :即将进入休眠。
  • kCFRunLoopAfterWaiting :刚从休眠中唤醒。
  • kCFRunLoopExit :退出 RunLoop

三、RunLoop 实现原理

1. RunLoop 运行的主要流程

  • 创建 CFRunLoopMode :初始化并添加各种事件源(Source、Timer、Observer)到对应的 Mode 中。
  • 运行 CFRunLoopRun 方法 :按如下步骤进行:
void CFRunLoopRun(void) {
    CFRunLoopRef rl = CFRunLoopGetCurrent();
    CFRunLoopRunSpecific(rl, kCFRunLoopDefaultMode, 1.0e10, false);  // 默认模式,无超时
}

void CFRunLoopRunSpecific(CFRunLoopRef rl, CFStringRef mode, CFTimeInterval seconds, Boolean returnAfterSourceHandled) {
    CFRunLoopModeRef currentMode = __CFRunLoopFindMode(rl, mode);
    if(!currentMode) return;

    while (1) {
        // 通知观察者即将进入 RunLoop
        __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopEntry);
        // 处理已到时间的定时器
        __CFRunLoopDoTimers(rl, currentMode, mach_absolute_time());
        // 处理输入源(Source0 和 Source1)
        __CFRunLoopDoSources(rl, currentMode, mach_absolute_time());
        // 通知观察者即将进入休眠
        __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopBeforeWaiting);
        // 进入休眠等待事件
        __CFRunLoopWait(rl, currentMode);
        // 从休眠中唤醒
        __CFRunLoopHandleWakeUpSources(rl, currentMode);
        // 通知观察者已从休眠中唤醒
        __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopAfterWaiting);
        // 处理定时器
        __CFRunLoopDoTimers(rl, currentMode, mach_absolute_time());
        // 处理输入源
        if(__CFRunLoopDoSources(rl, currentMode, mach_absolute_time())) break;
    }
    __CFRunLoopModeUnlock(currentMode);
}

2. 休眠和唤醒机制

RunLoop 的底层依靠系统 API 实现休眠和唤醒:

  • 休眠:使用 mach_msgselect 等系统调用,将线程睡眠,等待事件触发。
  • 唤醒:通过 mach_portCFRunLoopSource1 来唤醒线程。
void __CFRunLoopWait(CFRunLoopRef rl, CFRunLoopModeRef rlm) {
    mach_msg_timeout_t timeout = TIMEOUT_INFINITY; // 无限期等待
    int32_t result = mach_msg(..., timeout, ...);
    if (result == MACH_MSG_SUCCESS) {
        return result;
    }
}

四、应用场景的实现原理及代码

1. 保持后台线程存活

- (void)startBackgroundThread {
    [NSThread detachNewThreadSelector:@selector(threadEntryPoint) toTarget:self withObject:nil];
}

- (void)threadEntryPoint {
    @autoreleasepool {
        [[NSThread currentThread] setName:@"BackgroundThread"];
        NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
        [runLoop addPort:[NSPort port] forMode:NSDefaultRunLoopMode];
        [runLoop run];
    }
}

2. 管理定时器任务

NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timerMethod) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

3. 处理 UI 事件

UI 事件处理的核心在于主线程的 RunLoop,包含屏幕渲染、事件分发等。 Cocoa Touch 框架将这些操作都自动集成在主线程的 RunLoop 中,确保 UI 事件的及时响应。

// 主线程默认 RunLoop
[[NSRunLoop mainRunLoop] run];

4. 异步网络请求

网络请求使用 NSURLSession 的回调机制,可以在 RunLoop 中进行处理。

NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *task = [session dataTaskWithURL:[NSURL URLWithString:@"https://example.com"] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
    dispatch_async(dispatch_get_main_queue(), ^{
        if (data) {
            // 更新 UI
        }
    });
}];
[task resume];

5. 自动释放池的管理

每次 RunLoop 执行一次循环时,系统会自动构建和销毁一个自动释放池。

- (void)runLoopWithAutoreleasePool {
    while (self.keepRunning) {
        @autoreleasepool {
            [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
        }
    }
}

总结

通过深入分析 RunLoop 的底层实现,我们可以了解该机制如何高效地调度任务和处理事件,从而保持应用的响应性。掌握 RunLoop 的原理有助于开发者在日常编码中更高效地进行系统调优和解决复杂问题。

标签:__,定时器,iOS,currentMode,122,rl,RunLoop,mach
From: https://www.cnblogs.com/chglog/p/18307807

相关文章

  • iOS开发基础123-自动释放池
    自动释放池(AutoreleasePool)是Objective-C中用于管理内存的一个重要机制,它帮助开发者简化内存管理的工作。自动释放池的核心概念是将对象放入池中,在某个时刻由系统统一释放这些对象。这种机制在iOS和macOS的应用开发中广泛使用,尤其是在事件循环和线程运行时。为了深入理解其底层......
  • vue请求接口常用写法(axios)
    1.项目根目录下新建一个utils文件夹,并新建一个request.js文件(注意:是以axios方法请求的,所以需要先安装axios或cdn引入)安装:npmnpminstallaxios-Syarnyarnaddaxios-Scdn<scriptsrc="https://unpkg.com/axios/dist/axios.min.js"></script>&&配置代码imp......
  • iOS开发基础119-组件化
    一、引言组件化是将应用程序分解成多个独立模块的设计方法,这些模块可以单独开发、测试和维护。对于大型iOS项目,组件化能够提高开发效率、降低耦合、增加代码复用性,并且使项目更易维护。本文将详细介绍如何在iOS项目中实现组件化,包括本地组件管理和远程组件管理。二、为什么......
  • iOS开发基础120-通知与线程
    NSNotificationCenter是iOS和macOS开发中用于消息传递的机制,可以在多个对象之间实现解耦的事件通知。理解NSNotificationCenter的线程模型对正确使用这一工具至关重要。NSNotificationCenter的线程模型1.消息发送线程当你通过NSNotificationCenter发送消息时,消息会......
  • iOS开发基础108-Runtime
    Objective-C的Runtime是一个强大的特性,它让语言具备了很多灵活的动态能力。通过Runtime,开发者可以在运行时解析类、方法、变量,并进行动态的消息传递、方法交换等操作。以下将详细介绍Runtime,包括具体的应用场景和底层实现原理。什么是RuntimeRuntime是Objective-C运行......
  • iOS开发基础117-Hybrid
    HybridHybrid(混合)开发是一种结合了Web技术和原生应用开发技术的方法,旨在简化跨平台应用开发。通过Hybrid开发,开发者可以用HTML、CSS和JavaScript等前端技术编写代码,并将其运行在一个内嵌的浏览器环境中,从而实现跨平台的移动应用。什么是Hybrid开发?Hybrid开发主要是指将应用的用......
  • iOS开发基础116-性能监控
    在iOS开发中,性能监控是确保应用流畅运行和用户体验的关键。常用的性能监控工具能够帮助开发者实时监控系统性能,检测和诊断性能问题。下面列举几款常用的iOS性能监控工具,深入解析其底层原理、优缺点。1.InstrumentsInstruments是由Apple官方提供的用于性能分析和调试的工具。它......
  • iOS开发基础114-YYCache
    YYCache是一个高性能、易用的缓存组件,广泛用于iOS开发中。其设计宗旨是高效且灵活,可以处理不同类型的缓存需求。以下将介绍YYCache的常见应用场景,并深入分析其底层原理。应用场景1.图片缓存在展示大量图像的应用(比如社交媒体应用)中,缓存机制可以大幅减少网络请求,提升用户......
  • iOS开发基础115-Socket
    在现代网络编程中,Socket(套接字)是实现网络通信的主要机制。Socket提供了端到端的双向通信接口,使得不同主机上的进程能够通过网络直接通信。在iOS开发中,经常需要使用Socket进行网络请求、实时通信(如聊天、游戏等)。以下将详细介绍Socket的概念,并列举iOS开发中常用的三方Socket框架,深......
  • iOS开发基础113-Unity3D
    在iOS项目中接入Unity3D项目可以创建更复杂且互动性强的应用。Unity3D通常用于游戏开发,它可以与原生iOS项目进行集成。以下是详细的步骤和示例代码,且深入讨论其底层原理。步骤1.创建Unity3D项目打开Unity3D并创建一个新项目。完成项目场景和逻辑编写。在Unity3D项目中,设置i......