iOS中FPS的测量及其色彩表示

@Daniate  October 13, 2016

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的高低时,通常是红色表示低帧率绿色表示高帧率;橙色、黄色、黄绿色,表示高低之间的帧率。

为了将帧率转化为相应的颜色,最简单的方式就是使用HSBHSL色彩空间。

在这两个色彩空间中,H都是色相,它的取值范围是360°的圆心角。360°对应红色60°对应黄色120°对应绿色

在将帧率转化为颜色时,只需要改变H即可。

iOS中,苹果提供了HSB色彩空间所对应的方法,HSB取值被限制在[0, 1.0]区间内。

iOS 10之后(含iOS 10),不会对HSB的取值进行限制,对于[0, 1]区间外的值,会使用扩展的色彩空间

因此,在将帧率转化为颜色时,H的值可以用FPS / 60.0 * 120.0 / 360.0进行计算,也就是FPS / 180.0SB固定为1.0(也可以固定为与1.0非常相近的值)。

[UIColor colorWithHue:FPS / 180.0 saturation:1 brightness:1 alpha:1]

由于HSLHSB有一些区别,如果使用的是HSLL需要取值0.5(也可以取与0.5非常相近的值)。


评论已关闭