iOS开发过程中,我们有时需要监控主线程的卡顿情况,本文介绍主线程卡顿的实现方法。
新建MainThreadMonitor类,并且在.h中声明方法。
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface MainThreadMonitor : NSObject
+ (instancetype)sharedInstance;
- (void)start;
- (void)stop;
@end
NS_ASSUME_NONNULL_END
sharedInstance为单例方法,返回MainThreadMonitor类的实例。start为开始检测,stop为结束检测。
#import "MainThreadMonitor.h"
@interface MainThreadMonitor ()
@property(nonatomic, strong) dispatch_semaphore_t semaphore;
@property(nonatomic, assign) BOOL isMonitoring;
@property(nonatomic, assign) NSTimeInterval interval;
@property(nonatomic, assign) BOOL timeout;
@end
@implementation MainThreadMonitor
+ (instancetype)sharedInstance
{
static MainThreadMonitor *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[MainThreadMonitor alloc] init];
});
return sharedInstance;
}
- (void)start
{
self.isMonitoring = YES;
self.interval = 0.08;
self.semaphore = dispatch_semaphore_create(0);
__weak typeof (self) weakSelf = self;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
while (weakSelf.isMonitoring) {
weakSelf.timeout = YES;
dispatch_async(dispatch_get_main_queue(), ^{
weakSelf.timeout = NO;
dispatch_semaphore_signal(weakSelf.semaphore);
});
[NSThread sleepForTimeInterval:weakSelf.interval];
if (weakSelf.timeout) {
NSLog(@"Main thead is blocked");
}
dispatch_semaphore_wait(weakSelf.semaphore, DISPATCH_TIME_FOREVER);
}
});
}
- (void)stop
{
self.isMonitoring = NO;
}
@end
sharedInstance使用dispatch_once_t构建了单例方法。
isMonitoring属性代表当前是否在检测主线程卡顿状态。
interval为卡顿时间,当前设置为0.08s。
semaphore为信号量,用于控制当前轮次的检测是否完成。
timeout为超时标记,如果timeout为YES,代表主线程出现了卡顿。
监控方法的实现主要原理为开辟了一个子线程,在子线程内设置一个循环,不停地监控卡顿状态。在每次循环内部,获取主线程的队列然后设置timeout为NO,子线程sleep时间设置为80ms,如果子线程sleep结束时主线程还没有设置timeout,代表当前出现了卡顿。代码内部加入了信号量semaphore,主要控制当前卡顿检测出来以后,再进行下一次检测,防止一次卡顿被多次检测。