美文网首页ToolsiOS
iOS 学习笔记-卡顿监听

iOS 学习笔记-卡顿监听

作者: 妃雪 | 来源:发表于2017-03-23 15:51 被阅读34次

    (1) .h文件

    #import <Foundation/Foundation.h>
    @interface SMLagMonitor : NSObject
    + (instancetype)shareInstance;
    - (void)beginMonitor; //开始监视卡顿
    - (void)endMonitor;   //停止监视卡顿
    @end
    

    (2).m文件

    #import "SMLagMonitor.h"
    #import <CrashReporter/CrashReporter.h>
    
    @interface SMLagMonitor() {
        int timeoutCount;
        CFRunLoopObserverRef runLoopObserver;
        @public
        dispatch_semaphore_t dispatchSemaphore;
        CFRunLoopActivity runLoopActivity;
    }
    
    @end
    
    @implementation SMLagMonitor
    
    #pragma mark - Interface
    + (instancetype)shareInstance {
        static id instance = nil;
        static dispatch_once_t dispatchOnce;
        dispatch_once(&dispatchOnce, ^{
            instance = [[self alloc] init];
        });
        return instance;
    }
    
    - (void)beginMonitor {
        if (runLoopObserver) {
            return;
        }
        dispatchSemaphore = dispatch_semaphore_create(0); //Dispatch Semaphore保证同步
        //创建一个观察者
        CFRunLoopObserverContext context = {0,(__bridge void*)self,NULL,NULL};
        runLoopObserver = CFRunLoopObserverCreate(kCFAllocatorDefault,
                                                  kCFRunLoopAllActivities,
                                                  YES,
                                                  0,
                                                  &runLoopObserverCallBack,
                                                  &context);
        //将观察者添加到主线程runloop的common模式下的观察中
        CFRunLoopAddObserver(CFRunLoopGetMain(), runLoopObserver, kCFRunLoopCommonModes);
        
        //创建子线程监控
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            //子线程开启一个持续的loop用来进行监控
            while (YES) {
                long semaphoreWait = dispatch_semaphore_wait(dispatchSemaphore, dispatch_time(DISPATCH_TIME_NOW, 30*NSEC_PER_MSEC));
                if (semaphoreWait != 0) {
                    if (!runLoopObserver) {
                        timeoutCount = 0;
                        dispatchSemaphore = 0;
                        runLoopActivity = 0;
                        return;
                    }
                    //两个runloop的状态,BeforeSources和AfterWaiting这两个状态区间时间能够检测到是否卡顿
                    if (runLoopActivity == kCFRunLoopBeforeSources || runLoopActivity == kCFRunLoopAfterWaiting) {
                        //出现三次出结果
                        if (++timeoutCount < 3) {
                            continue;
                        }
                        
                        NSData *lagData = [[[PLCrashReporter alloc]
                                              initWithConfiguration:[[PLCrashReporterConfig alloc] initWithSignalHandlerType:PLCrashReporterSignalHandlerTypeBSD symbolicationStrategy:PLCrashReporterSymbolicationStrategyAll]] generateLiveReport];
                        PLCrashReport *lagReport = [[PLCrashReport alloc] initWithData:lagData error:NULL];
                        NSString *lagReportString = [PLCrashReportTextFormatter stringValueForCrashReport:lagReport withTextFormat:PLCrashReportTextFormatiOS];
                        //将字符串上传服务器
                        NSLog(@"lag happen, detail below: \n %@",lagReportString);
                    } //end activity
                }// end semaphore wait
                timeoutCount = 0;
            }// end while
        });
        
    }
    
    - (void)endMonitor {
        if (!runLoopObserver) {
            return;
        }
        CFRunLoopRemoveObserver(CFRunLoopGetMain(), runLoopObserver, kCFRunLoopCommonModes);
        CFRelease(runLoopObserver);
        runLoopObserver = NULL;
    }
    
    #pragma mark - Private
    static void runLoopObserverCallBack(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info){
        SMLagMonitor *lagMonitor = (__bridge SMLagMonitor*)info;
        lagMonitor->runLoopActivity = activity;
        
        dispatch_semaphore_t semaphore = lagMonitor->dispatchSemaphore;
        dispatch_semaphore_signal(semaphore);
    }
    

    (3)调用方法 在AppDelegate中调用

      //卡顿监测
        [[SMLagMonitor shareInstance] beginMonitor];
    

    相关文章

      网友评论

        本文标题:iOS 学习笔记-卡顿监听

        本文链接:https://www.haomeiwen.com/subject/gcttottx.html