使用 UITableView 时,发现滚动时的性能还不错,但来回滚动时,第一次显示的图像不如再次显示的图像流畅,出现前会有稍许的停顿感。

于是猜想显示过的图像肯定是被缓存起来了,查了下文档后发现果然如此。在《Improving Image Drawing Performance on iOS》一文中找到了一些提示:原来在显示图像时,解压和重采样会消耗很多 CPU 时间;而如果预先在一个 bitmap context 里画出图像,再缓存这个图像,就能省去这些繁重的工作了。

接着下面举个例子程序来验证:

#import <UIKit/UIKit.h>

@interface ImageView : UIView
@property (nonatomic, strong) UIImage * image;
@end #import "ImageView.h"
#include <mach/mach_time.h> static const CGRect imageRect = { {0, 0}, {100, 100}}; @implementation ImageView - (void)awakeFromNib
{
if (!self.image) {
self.image = [UIImage imageNamed:@"xxx"];
}
[superawakeFromNib];
} - (void)drawRect:(CGRect)rect
{
if (CGRectContainsRect(rect, imageRect)) { uint64_t start = getTickCount(); [self.image drawInRect:imageRect]; uint64_t drawTime = getTickCount() - start; NSLog(@"%llu", drawTime);  // 打印时间间隔   
}
} // mach_absolute_time() 的单位是 Mach absolute time unit,而不是纳秒。它们之间的换算关系和 CPU 相关,不是一个常量。最简单的办法是用 CoreServices 框架的 AbsoluteToNanoseconds 和 AbsoluteToDuration 函数来转换。此外也可以用 mach_timebase_info 函数来获取这个比值。
uint64_t getTickCount(void)
{
static mach_timebase_info_data_t sTimebaseInfo; uint64_t machTime = mach_absolute_time(); // Convert to nanoseconds - if this is the first time we've run, get the timebase.
if (sTimebaseInfo.denom == 0) {
(void)mach_timebase_info(&sTimebaseInfo);
} uint64_t millis = (machTime * sTimebaseInfo.numer) / sTimebaseInfo.denom;  // 纳秒 return millis;
} @end

测试用一张 1838 * 890 的图

2018-07-05 11:05:25.950978+0800 Demo[5831:113872] 31802012

接下来就是见证奇迹的时刻了,把这段代码加入程序:

static const CGSize imageSize = {100, 100};

- (void)awakeFromNib 
{
if (!self.image) {
self.image = [UIImage imageNamed:@"xxx"]; // 由于JPEG图像是不透明的,所以第二个参数就设为YES
// 第三个参数是缩放比例。虽然这里可以用 [UIScreen mainScreen].scale 来获取,但实际上设为 0 后,系统就会自动设置正确的比例了
UIGraphicsBeginImageContextWithOptions(imageSize, YES, 0);
// 将图像画到当前的 image context 里,此时就完成了解压缩和重采样的工作
[image drawInRect:imageRect];
self.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
}

值得一提的是,图像本身也有缩放比例,普通的图像是 1.0(除了 imageNamed: 外,大部分 API 都只能获得这种图像,而且缩放比例是不可更改的),高清图像是 2.0。图像的点和屏幕的像素就是依靠两者的缩放比例来计算的,例如普通图像在视网膜显示屏上是 1:4,而高清图像在视网膜显示屏上则是 1:1。

时间间隔:2018-07-05 11:30:46.284490+0800 Demo[6401:133240] 127939,缩短了很多。

还能更快吗?让我们来试试 Core Graphics。

先定义一个全局的 CGImageRef 变量:

static CGImageRef imageRef;

- (void)awakeFromNib
{
imageRef = self.image.CGImage;
}

然后

- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextDrawImage(context, imageRect, imageRef);
}

运行一下,发现时间间隔为 2018-07-05 11:36:19.837131+0800 Demo[6677:139386] 27425265,而且图像还上下颠倒了⋯

这个原因是 UIKit 和 Core Graphics 的坐标系 y 轴是相反的,于是加上下面代码来修正:

CGContextRef context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, 0, 100);
CGContextScaleCTM(context, 1, -1);
CGContextDrawImage(context, imageRect, imageRef);

这下图像终于正常显示了,时间增加到了 2018-07-05 11:39:27.557629+0800 Demo[6817:142712] 34242146,成效不大,看来直接用 -drawAtPoint: 和 -drawInRect: 就足够好了。

iOS 预渲染加速图像显示的更多相关文章

  1. 利用预渲染加速iOS设备的图像显示

    最近在做一个UITableView的例子,发现滚动时的性能还不错.但来回滚动时,第一次显示的图像不如再次显示的图像流畅,出现前会有稍许的停顿感.于是我猜想显示过的图像肯定是被缓存起来了,查了下文档后发 ...

  2. iOS 图像渲染原理

    http://chuquan.me/2018/09/25/ios-graphics-render-principle/ 通过 图形渲染原理 一文,大致能够了解图形渲染过程中硬件相关的原理.本文将进一步 ...

  3. 前端性能和加载体验优化实践(附:PWA、离线包、内存优化、预渲染)

    一.背景:页面为何会卡? 1.1 等待时间长(性能) 项目本身包/第三方脚本比较大. JavaScript 执行阻塞页面加载. 图片体积大且多. 特别是对于首屏资源加载中的白屏时间,用户等待的时间就越 ...

  4. vue预渲染及其cdn配置

    VUE SEO方案一 - 预渲染及其cdn配置 项目接入VUE这样的框架后,看起来真是太漂亮了,奈何与MCV框架比起来,单页应用程序却满足不了SEO的业务需求,首屏渲染时间也是个问题.总不能白学VUE ...

  5. Prerender.io - 预渲染架构,提高AngularJS SEO

    近些年来,越来越多的JavaScript框架(即AngularJS,BackboneJS,ReactJS)变得越来越流行.许多公司和开发人员使用这些JavaScript框架开发应用程序.这些框架有很多 ...

  6. 服务端预渲染之Nuxt (使用篇)

    服务端预渲染之Nuxt - 使用 现在大多数开发都是基于Vue或者React开发的,能够达到快速开发的效果,也有一些不足的地方,Nuxt能够在服务端做出渲染,然后让搜索引擎在爬取数据的时候能够读到当前 ...

  7. 服务端预渲染之Nuxt(介绍篇)

    现在前端开发一般都是前后端分离,mvvm和mvc的开发框架,如Angular.React和Vue等,虽然写框架能够使我们快速的完成开发,但是由于前后台分离,给项目SEO带来很大的不便,搜索引擎在检索的 ...

  8. vue项目使用 prerender-spa-plugin 预渲染

    由于项目要做seo优化,而用vue写成的spa页面谷歌浏览器等是抓取不到数据的.介于ssr和预渲染来说,后者相对来说要简单许多.所以采用了预渲染方式.采用插件prerender-spa-plugin使 ...

  9. vue 预渲染遇到的坑

    前言: 最近公司项目需要增加seo搜索引擎优化,到网上找了下资料,有预渲染和服务端渲染两种方式,考虑到只需要渲染首页所以我选择了先启用比较简单的预渲染方式来做seo! 步骤: 1.安装 prerend ...

随机推荐

  1. mysql 存储过程 执行存储过程修改了表中所有行的信息

    存储过程中的where条件语句,如果传入的参数和表字段名相同,存储过程就会把这个约束条件忽略.小结:存储过程中传递的参数名不要和字段名相同.特别是修改.删除等操作,可能会对整张表产生影响.后果会很严重 ...

  2. css 进度条的文字根据进度渐变

    需求 1.进度条里面的文字需要根据进度的长度而变化 原理 用两个一模一样的样式的 div 重叠起来 效果 字体开始为 蓝色,跟随进度条变为 白色 在线预览: https://jsfiddle.net/ ...

  3. xml模块介绍

      # xml 是一门可拓展的语言 # xml 语法 是用<>包裹的起来的<>就是标签, xml可以由多个<>组成 也可以由单个<>组成, # < ...

  4. Java实现生产者消费者(一)

    问题描述:生产者和消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内共用同一个存储空间,生产者往存储空间中添加产品,消费者从存储空间中取走产品,当存储空间为空时,消费者阻塞,当存储空间满时 ...

  5. flask修改flask_wtf使其支持json数据的validation验证

    flask默认是前后端不分离策略,前端通过flask+wtf表单来传递post,put...等数据. 现在前后端分离是趋势,那么对flask进行一定的修改,变为前后端分离,在前端页面中请求后端,那么请 ...

  6. openstack的yum源出错,配置openstack-ocata版的在线yum源,openstack的yum源配置

    真的是几经周折,终于配置好了!我做好了一键配置yum的代码,地址:https://www.cnblogs.com/guarding/p/12321702.html 首先看一下配置前的报错信息把: 需要 ...

  7. nginx升级不改变配置文件

    查看当前版本是:1.10.3 [root@proxy nginx-1.10.3]# /usr/local/nginx/sbin/nginx -Vnginx version: nginx/1.10.3b ...

  8. Linux系统之LNMP及nginx反向代理实现

    1.编译安装LNMP,并安装wordpress 首先准备环境,编译安装LNMP可以是多台主机,也可以是单台主机,把nginx,mysql,php都集中安装在一个主机上:我这里以一台主机为例吧!! 一. ...

  9. PostgreSQL查询表以及字段的备注

    目录 查询所有表名称以及字段含义 查看所有表名 查看表名和备注 查看特定表名备注 查看特定表名字段 查询所有表名称以及字段含义 select c.relname 表名,cast(obj_descrip ...

  10. IPFS(星际文件系统)-初步接触

    〇.IPFS介绍 从HTTP到IPFS,星际文件系统能变革信息传播的方式吗? 戴嘉乐:详解IPFS的本质.技术架构以及应用 以下为实现相关摘要 1.存储 在IPFS中,信息可以存储进IPFS系统中的块 ...