首页 > 其他分享 >iOS开发基础124-RunLoop实现卡顿检测

iOS开发基础124-RunLoop实现卡顿检测

时间:2024-07-17 17:09:21浏览次数:14  
标签:observer strongSelf iOS dispatch 124 卡顿 semaphore RunLoop

利用 RunLoop 实现卡顿检测的基本思路是通过监听 RunLoop 的状态变化来判断主线程的执行时长。如果 RunLoop 在某个状态停留的时间超过了预设的时间阈值,则认为发生了卡顿。在具体实现中,可以利用 CFRunLoopObserver 来监听 RunLoop 的状态变化,并记录时间差。

一、卡顿检测的基本原理

在 iOS 应用中,RunLoop 对主线程事件的处理可以细分为多个状态,包括 beforeSourcesafterWaiting 等。通过添加 CFRunLoopObserver,我们可以在 RunLoop 进入和退出这些状态时执行自定义代码:

  • beforeSources:即将在处理 Source 事件前触发。
  • afterWaiting:从休眠状态唤醒后触发。

通过在这两个状态之间记录时间差,如果该时间差超过预设的阈值(如 200ms),则认为发生了卡顿。

二、实现步骤

  1. 创建并配置 CFRunLoopObserver
  2. 监听适当的 RunLoop 状态
  3. 记录时间并判断卡顿
  4. 记录卡顿信息

三、卡顿检测封装示例

以下是一个利用 RunLoop 实现卡顿检测的完整示例,并进行了封装:

#import <Foundation/Foundation.h>
#import <CoreFoundation/CoreFoundation.h>

@interface LagMonitor : NSObject {
    CFRunLoopObserverRef _observer;
    CFRunLoopActivity _activity;
    dispatch_semaphore_t _semaphore;
    NSTimeInterval _threshold; // 时间阈值 (单位: 秒)
}

@property (nonatomic, assign) BOOL isMonitoring;

+ (instancetype)sharedInstance;
- (void)startMonitoring;
- (void)stopMonitoring;

@end

@implementation LagMonitor

+ (instancetype)sharedInstance {
    static LagMonitor *instance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[LagMonitor alloc] init];
    });
    return instance;
}

- (instancetype)init {
    self = [super init];
    if (self) {
        _semaphore = dispatch_semaphore_create(0);
        _threshold = 0.2; // 默认阈值 200ms
        _activity = 0;
    }
    return self;
}

- (void)startMonitoring {
    if (self.isMonitoring) return;
    self.isMonitoring = YES;

    CFRunLoopObserverContext context = {0, (__bridge void *)self, NULL, NULL, NULL};

    _observer = CFRunLoopObserverCreate(kCFAllocatorDefault,
                                        kCFRunLoopAllActivities,
                                        YES,
                                        0,
                                        &runLoopObserverCallBack,
                                        &context);

    if (_observer) {
        CFRunLoopRef runLoop = CFRunLoopGetMain();
        CFRunLoopAddObserver(runLoop, _observer, kCFRunLoopCommonModes);

        // 开启一个子线程用于时间监控
        __weak typeof(self) weakSelf = self;
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
            __strong typeof(weakSelf) strongSelf = weakSelf;
            while (strongSelf && strongSelf.isMonitoring) {
                long result = dispatch_semaphore_wait(strongSelf->_semaphore, dispatch_time(DISPATCH_TIME_NOW, strongSelf->_threshold * NSEC_PER_SEC));
                if (result != 0) {
                    if (!strongSelf->_observer) {
                        strongSelf->_semaphore = 0;
                        strongSelf->_activity = 0;
                        return;
                    }
                    if (strongSelf->_activity == kCFRunLoopBeforeSources || strongSelf->_activity == kCFRunLoopAfterWaiting) {
                        // 检测到卡顿,记录或上报卡顿信息
                        [strongSelf logLag];
                    }
                }
            }
        });
    }
}

- (void)stopMonitoring {
    if (!self.isMonitoring) return;
    self.isMonitoring = NO;

    if (_observer) {
        CFRunLoopRemoveObserver(CFRunLoopGetMain(), _observer, kCFRunLoopCommonModes);
        CFRelease(_observer);
        _observer = NULL;
    }
    // 销毁信号量
    _semaphore = nil;
}

void runLoopObserverCallBack(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info) {
    LagMonitor *monitor = (__bridge LagMonitor *)info;
    monitor->_activity = activity;
    dispatch_semaphore_signal(monitor->_semaphore);
}

- (void)logLag {
    // 打印或记录卡顿信息
    NSLog(@"Detect a lag!");
}

@end

四、使用示例

#import "LagMonitor.h"

// 在应用启动或适当时机启用卡顿监控
[[LagMonitor sharedInstance] startMonitoring];

// 停止监控
[[LagMonitor sharedInstance] stopMonitoring];

五、关键点解析

  1. CFRunLoopObserver 使用

    • CFRunLoopObserverCreate 用于创建 RunLoop 观察者,并配置所关心的状态变化。
    • CFRunLoopObserverContext 提供了上下文信息,以便在回调中使用。
  2. 线程监控

    • 通过 GCD 创建一个高优先级的子线程时刻等待 RunLoop 状态的变化。
    • 使用 dispatch_semaphore 实现线程间同步,并通过信号量判断 RunLoop 是否在某状态间隔超时。
  3. 阈值设置

    • _threshold 是用来设置卡顿的时间阈值,例如 0.2 秒可以检测超过 200 毫秒的卡顿。
  4. 封装接口

    • 提供 startMonitoringstopMonitoring 方法,可以方便地启动和停止监测卡顿。

六、总结

通过利用 RunLoop 的观察者功能,我们能够准确地捕捉到 RunLoop 的状态变化,并通过时间阈值来判断卡顿现象。这种方法可以帮助我们在开发和调试过程中及时发现和解决性能问题,提高应用的响应速度和用户体验。这种封装方式也使得卡顿检测的启用和停止变得简单易用,适合集成到各种 iOS 项目中。

标签:observer,strongSelf,iOS,dispatch,124,卡顿,semaphore,RunLoop
From: https://www.cnblogs.com/chglog/p/18307840

相关文章

  • iOS开发基础122-RunLoop
    深入探讨RunLoop的底层实现需要了解CoreFoundation框架中的CFRunLoop以及与RunLoop工作机制紧密相关的操作系统底层API。这些底层实现主要涉及到事件源、定时器和线程的调度机制。本文将深入剖析RunLoop的底层结构及其运行流程。一、RunLoop底层数据结构涉及RunLo......
  • iOS开发基础123-自动释放池
    自动释放池(AutoreleasePool)是Objective-C中用于管理内存的一个重要机制,它帮助开发者简化内存管理的工作。自动释放池的核心概念是将对象放入池中,在某个时刻由系统统一释放这些对象。这种机制在iOS和macOS的应用开发中广泛使用,尤其是在事件循环和线程运行时。为了深入理解其底层......
  • 基于java+springboot+vue实现的中药实验管理系统(文末源码+Lw)124
    基于SpringBoot+Vue的实现的中药实验管理系统(源码+数据库+万字Lun文+流程图+ER图+结构图+开题报告+演示视频+软件包)系统功能:本中药实验管理系统有管理员,教师,学生,实验员。管理员功能有个人中心,学生管理,教师管理,实验员管理,实验教学管理,在线学习管理,实验信息管理,实验预约管理,实......
  • 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.图片缓存在展示大量图像的应用(比如社交媒体应用)中,缓存机制可以大幅减少网络请求,提升用户......