iOS-屏幕帧数

在看YYKit (https://github.com/ibireme/YYKit)代码时,发现项目里有一个查看当前屏幕帧数的小工具YYFPSLabel,能够实时查看当前的帧数。

iOS-屏幕帧数_第1张图片
作者yehot的gif

以下是YYFPSLabel重要代码:

  /**
     //创建一个CADisplayLink,用于获取帧数

     @param tick: 获取数据方法

     @return
     */
    _link = [CADisplayLink displayLinkWithTarget:[YYWeakProxy proxyWithTarget:self] selector:@selector(tick:)];
    
    //放到RunLoop中
    [_link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
 //获取帧数方法
- (void)tick:(CADisplayLink *)link {
    if (_lastTime == 0) {
        _lastTime = link.timestamp;
        return;
    }
    
    _count++;
    NSTimeInterval delta = link.timestamp - _lastTime;
    if (delta < 1) return;
    _lastTime = link.timestamp;
    
    //获取当前fps
    float fps = _count / delta;
    _count = 0;
    
    //UILabel富文本
    CGFloat progress = fps / 60.0;
    UIColor *color   = [UIColor colorWithHue:0.27 * (progress - 0.2) saturation:1 brightness:0.9 alpha:1];
    
    NSMutableAttributedString *text = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"%d FPS",(int)round(fps)]];
    [text setColor:color range:NSMakeRange(0, text.length - 3)];
    [text setColor:[UIColor whiteColor] range:NSMakeRange(text.length - 3, 3)];
    text.font = _font;
    [text setFont:_subFont range:NSMakeRange(text.length - 4, 1)];
    self.attributedText = text;
}

详见代码

YYWeakProxy 这个类是用于保存一个弱的对象。它可以用来避免保留周期,如目标NSTimer或CADisplayLink。

为什么需要这么使用呢?
因为

CADisplayLink *_link = [CADisplayLink displayLinkWithTarget:self selector:@selector(tick:)];
[NSTimer timerWithTimeInterval:1.f target:self selector:@selector(tick:) userInfo:nil repeats:YES];

当使用以上代码的时候会导致循环引用,

__weak typeof(self) weakSelf = self;
_link = [CADisplayLink displayLinkWithTarget:weakSelf selector:@selector(tick:)];

使用weakself的时候,当界面退出之后计时器还在使用。

如何解决这个问题呢?
解决方法
1.使用YYWeakProxy提供的方法,释放计时器。
2.自己代码控制在合适的时候停止计时器。

总结

在学习YYFPSLabel中,学习了很多知识。

  • 使用NSTimer
    如果我们在界面上滚动一个scrollview,那么我们会发现在停止滚动前,控制台不会有任何输出,就好像scrollView在滚动的时候将timer暂停了一样。
    其实是runloop的mode在做怪。
    NSTimer与NSURLConnection默认运行在default mode下,这样当用户在拖动UITableView处于UITrackingRunLoopMode模式时,NSTimer不能fire,NSURLConnection的数据也无法处理。
    如果不使用YYWeakProxy,则需要将link放到runloop中。
    [_link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
  • CADisplayLink
    这是一个定时器绑定到vsync显示,类似NSTimer。
    它总是在屏幕完成一次更新之前启动,它的接口设计的和NSTimer很类似,所以它实际上就是一个内置实现的替代,但是和timeInterval以秒为单位不同,CADisplayLink有一个整型的frameInterval属性,指定了间隔多少帧之后才执行。默认值是1,意味着每次屏幕更新之前都会执行一次。但是如果动画的代码执行起来超过了六十分之一秒,你可以指定frameInterval为2,就是说动画每隔一帧执行一次(一秒钟30帧)或者3,也就是一秒钟20次。

  • FPS

 The maximum fps in OSX/iOS Simulator is 60.00.
 The maximum fps on iPhone is 59.97.
 The maxmium fps on iPad is 60.0.
  • 参考
    http://www.jianshu.com/p/878bfd38666d
    https://github.com/ibireme/YYKit/blob/master/Demo/YYKitDemo/YYFPSLabel.m
    http://blog.csdn.net/yuquan0821/article/details/16843195
    https://zsisme.gitbooks.io/ios-/content/chapter11/frame-timing.html
    http://www.jianshu.com/p/c35a81c3b9eb

你可能感兴趣的:(iOS-屏幕帧数)