FPS的测量
对于FPS
的测量,就是使用CADisplayLink
计算某个时间段内某个方法的调用次数:
FPS = 调用次数 / 时间
#import <UIKit/UIKit.h>
@interface FPSMeasurer : NSObject
+ (FPSMeasurer *)measurer;
@property (nonatomic, getter=isPaused) BOOL paused;
@property (nonatomic, assign) NSTimeInterval reportInterval;// default is 1, >= 0.1
@property (nonatomic, copy) void (^reportBlock)(double fps, UIColor *fpsColor);
@end
#import "FPSMeasurer.h"
#import <QuartzCore/QuartzCore.h>
@interface FPSMeasurer ()
@property (nonatomic, strong) CADisplayLink *displayLink;
@property (nonatomic, assign) NSTimeInterval lastTimestamp;
@property (nonatomic, assign) NSUInteger frames;
@end
@implementation FPSMeasurer
static FPSMeasurer *measurer = nil;
+ (FPSMeasurer *)measurer {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
measurer = [[super allocWithZone:NULL] init];
});
return measurer;
}
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
return [FPSMeasurer measurer];
}
- (instancetype)init {
if (self = [super init]) {
_reportInterval = 1;
_displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayLinkSelector:)];
[_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
}
return self;
}
- (void)displayLinkSelector:(CADisplayLink *)displayLink {
++self.frames;
if (self.lastTimestamp < DBL_EPSILON) {
self.lastTimestamp = displayLink.timestamp;
} else {
NSTimeInterval time = displayLink.timestamp - self.lastTimestamp;
if (time >= self.reportInterval) {
self.lastTimestamp = displayLink.timestamp;
NSUInteger frames = self.frames;
self.frames = 0;
if (self.reportBlock) {
double fps = frames / time;
self.reportBlock(fps, [UIColor colorWithHue:fps / 180.0 saturation:1 brightness:1 alpha:1]);
}
}
}
}
- (void)setReportInterval:(NSTimeInterval)reportInterval {
dispatch_block_t block = ^{
if (_reportInterval != reportInterval) {
_reportInterval = MAX(reportInterval, 0.1);
}
};
if ([NSThread isMainThread]) {
block();
} else {
dispatch_sync(dispatch_get_main_queue(), block);
}
}
- (void)setPaused:(BOOL)paused {
dispatch_block_t block = ^{
if (_paused != paused) {
_paused = paused;
_displayLink.paused = paused;
}
};
if ([NSThread isMainThread]) {
block();
} else {
dispatch_sync(dispatch_get_main_queue(), block);
}
}
@end
FPS的色彩表示
在用颜色展现FPS
的高低时,通常是红色
表示低帧率
;绿色
表示高帧率
;橙色、黄色、黄绿色,表示高低之间的帧率。
为了将帧率转化为相应的颜色,最简单的方式就是使用HSB
或HSL
色彩空间。
在这两个色彩空间中,H
都是色相,它的取值范围是0°
到360°
的圆心角。0°
与360°
对应红色
、60°
对应黄色
、120°
对应绿色
。
在将帧率转化为颜色时,只需要改变H
即可。
在iOS
中,苹果提供了HSB
色彩空间所对应的方法,H
、S
、B
取值被限制在[0, 1.0]
区间内。
在
iOS 10
之后(含iOS 10
),不会对H
、S
、B
的取值进行限制,对于[0, 1]
区间外的值,会使用扩展的色彩空间
因此,在将帧率转化为颜色时,H
的值可以用FPS / 60.0 * 120.0 / 360.0
进行计算,也就是FPS / 180.0
,S
、B
固定为1.0
(也可以固定为与1.0
非常相近的值)。
[UIColor colorWithHue:FPS / 180.0 saturation:1 brightness:1 alpha:1]
由于HSL
与HSB
有一些区别,如果使用的是HSL
,L
需要取值0.5
(也可以取与0.5
非常相近的值)。