app优化篇
Time Profiler分析原理:它按照固定的时间间隔来跟踪每一个线程的堆栈信息,通过统计比较时间间隔之间的堆栈状态,来推算某个方法执行了多久,并获得一个近似值。
平常采用instrument中的core animation进行性能检测
着重优化点:
1、图层的混合:"Color Blended Layers"正是用于检测哪里发生了图层混合,并用红色标记出来。
控件不要设置透明度,默认值opaque = true,记得设置控件的backgroundColor。确保UIImage没有alpha通道。
2、光栅化:Color Hits Green and Misses Red”,它表示如果命中缓存则显示为绿色,否则显示为红色
将一个layer预先渲染成位图(bitmap),然后加入缓存中。如果对于阴影效果这样比较消耗资源的静态内容进行缓存,可以得到一定幅度的性能提升。
光栅化仅适用于较复杂的、静态的效果。
3、正确的图片格式:比如png,jpeg。从网络下载的图片,而GPU恰好不支持这个格式,这就需要CPU预先进行格式转化。“Color Copied Images”就用来检测这种实时的格式转化,如果有则会将图片标记为蓝色。
4、正确的图片尺寸:“Color Misaligned Images”。它表示如果图片需要缩放则标记为黄色,如果没有像素对齐则标记为紫色。
5、离屏渲染:“Color Offscreen-Rendered Yellow”会把需要离屏渲染的地方标记为黄色。
6、手动进行图片解码:采用异步绘制,在display中进行图片的解码操作,主要使用bitmap和colorspace等手段。
7、尤其在scrollview中避免使用xib:直接从代码创建和读文件创建,肯定读文件要慢很多,
8、尤其在复杂视图中不使用autolayout:增加cpu的计算任务
9、采用coretext代替label:label需要计算他的size,进行布局
10、避免动态创建视图:懒加载,设置hidden属性
11、必要时layer代替view:
12、复杂视图必要时合为一张图片处理:
13、异步操作db,计算等工作
14、通知,VoIP,定位,蓝牙等都会使设备从 Standby 状态唤起
15、imageNamed: 与 imageWithContentsOfFile:的差异
16、少用NSDateFormatter
17、不要随意使用 NSLog()
18、[NSFileManager attributesOfItemAtPath:error:] 会浪费大量时间读取可能根本不需要的附加属性:
#import <sys/stat.h>
struct stat statbuf;
const char *cpath = [filePath fileSystemRepresentation];
if (cpath && stat(cpath, &statbuf) == ) {
NSNumber *fileSize = [NSNumber numberWithUnsignedLongLong:statbuf.st_size];
NSDate *modificationDate = [NSDate dateWithTimeIntervalSince1970:statbuf.st_mtime];
NSDate *creationDate = [NSDate dateWithTimeIntervalSince1970:statbuf.st_ctime];
// etc
}
19、内存泄漏工具:MLeakFinder
20、尽量少使用定时器:会频繁唤醒runloop执行任务
21、异步绘制:VVeboTableViewDemo :异步计算空间frame,将不交互的空间绘制到一张图片中
21、tableview方面:
高度缓存:预先layout、或者UITableView-FDTemplateLayoutCell
cell中不要使用drawRect绘制图片,改用CALayer的-drawInContext:Core Animation将会为这个图层申请一个后备存储,用来保存那些方法绘制进来的位图。那些方法内的代码将会运行在 CPU上,结果将会被上传到GPU。
按需加载:VVeboTableViewDemo : 监听runloop的default模式,预加载指定行的样式
离屏渲染:
真正的离屏渲染发生在GPU。
如果要在显示屏上显示内容,我们至少需要一块与屏幕像素数据量一样大的frame buffer,作为像素数据存储区域,而这也是GPU存储渲染结果的地方。如果有时因为面临一些限制,无法把渲染结果直接写入frame buffer,而是先暂存在另外的内存区域,之后再写入frame buffer,那么这个过程被称之为离屏渲染。
常见的触发离屏渲染场景:
1、cornerRadius+clipsToBounds:
容器的子layer因为父容器有圆角,那么也会需要被裁剪,而这时它们还在渲染队列中排队,尚未被组合到一块画布上,自然也无法统一裁剪。
此时我们就不得不开辟一块独立于frame buffer的空白内存,先把容器以及其所有子layer依次画好,然后把四个角“剪”成圆形,再把结果画到frame buffer中。
2、shadow:
阴影默认是作用在其中”非透明区域“的,而且需要显示在所有layer内容的下方,阴影的本体(layer和其子layer)都还没有被组合到一起,怎么可能在第一步就画出只有完成最后一步之后才能知道的形状呢?这样一来又只能另外申请一块内存,把本体内容都先画好,再根据渲染结果的形状,添加阴影。不过如果我们能够预先告诉CoreAnimation(通过shadowPath属性)阴影的几何形状,那么阴影当然可以先被独立渲染出来,不需要依赖layer本体。
3、group opacity:
alpha并不是分别应用在每一层之上,而是只有到整个layer树画完之后,再统一加上alpha,最后和底下其他layer的像素进行组合。显然也无法通过一次遍历就得到最终结果。
4、mask:
我们知道mask是应用在layer和其所有子layer的组合之上的,而且可能带有透明度,那么其实和group opacity的原理类似。
5、渐变。
6、shouldRasterize
尽管离屏渲染开销很大,但是当我们无法避免它的时候,可以想办法把性能影响降到最低。
shouldRasterize。一旦被设置为true,Render Server就会强制把layer的渲染结果(包括其子layer,以及圆角、阴影、group opacity等等)保存在一块内存中,这样一来在下一帧仍然可以被复用,而不会再次触发离屏渲染。
layer的内容(包括子layer)必须是静态的,因为一旦发生变化(如resize,动画),之前辛苦处理得到的缓存就失效了。
如果layer的子结构非常复杂,渲染一次所需时间较长,同样可以打开这个开关,把layer绘制到一块缓存,然后在接下来复用这个结果,这样就不需要每次都重新绘制整个layer树了。
开启“Color Hits Green and Misses Red”来检查该场景下光栅化操作是否是一个好的选择。绿色表示缓存被复用,红色表示缓存在被重复创建。
启动和优化:
iOS的启动流程
1、根据 info.plist 里的设置加载闪屏,建立沙箱,对权限进行检查等
2、加载可执行文件
3、加载动态链接库,进行 rebase 指针调整和 bind 符号绑定
4、Objc 运行时的初始处理,包括 Objc 相关类的注册、category 注册、selector 唯一性检查等;
5、初始化,包括了执行 +load() 方法、attribute((constructor)) 修饰的函数的调用、创建 C++ 静态全局变量。
6、执行 main 函数
7、Application 初始化,到 applicationDidFinishLaunchingWithOptions 执行完
8、初始化帧渲染,到 viewDidAppear 执行完,用户可见可操作。
启动优化
1、减少动态库的加载
2、减少系统库和第三方库的加载
3、去除掉无用的类和C++全局变量的数量,减少项目文件中Category,静态变量等的使用数量
4、尽量让load方法中的内容放到首屏渲染之后再去执行,或者使用initialize替换
5、去除在首屏展现之前非必要的功能
6、检查首屏展现之前主线程的耗时方法,将没必要的耗时方法滞后或者延迟执行
AutoLayout:

- 预编译:主要处理以“#”开始的预编译指令。
- 编译:
- 词法分析:将字符序列分割成一系列的记号。
- 语法分析:根据产生的记号进行语法分析生成语法树。
- 语义分析:分析语法树的语义,进行类型的匹配、转换、标识等。
- 中间代码生成:源码级优化器将语法树转换成中间代码,然后进行源码级优化,比如把 1+2 优化为 3。中间代码使得编译器被分为前端和后端,不同的平台可以利用不同的编译器后端将中间代码转换为机器代码,实现跨平台。
- 目标代码生成:此后的过程属于编译器后端,代码生成器将中间代码转换成目标代码(汇编代码),其后目标代码优化器对目标代码进行优化,比如调整寻址方式、使用位移代替乘法、删除多余指令、调整指令顺序等。
- 汇编:汇编器将汇编代码转变成机器指令。
- 静态链接:链接器将各个已经编译成机器指令的目标文件链接起来,经过重定位过后输出一个可执行文件。
- 装载:装载可执行文件、装载其依赖的共享对象。
- 动态链接:动态链接器将可执行文件和共享对象中需要重定位的位置进行修正。
- 最后,进程的控制权转交给程序入口,程序终于运行起来了。
异步绘制:
改变frame、更新UIView/CALayer,或者自己去调用setNeedsLayout/setNeedsDisplay方法,内部调用流程为:
当前runloop即将结束的时候调用CALayer的display方法;

系统绘制流程为:

CGBitmapContextCreate()可以创建一个CGCentextRef,在异步线程使用这个context进行绘制。- (void)display {
dispatch_async(backgroundQueue, ^{
UIGraphicsBeginImageContextWithOptions(size, NO, scale);
///获取当前上下文
CGContextRef context = UIGraphicsGetCurrentContext();
///将坐标系反转
CGContextSetTextMatrix(context, CGAffineTransformIdentity);
///文本沿着Y轴移动
CGContextTranslateCTM(context, 0, size.height);
///文本反转成context坐标系
CGContextScaleCTM(context, 1.0, -1.0);
///创建绘制区域
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddRect(path, NULL, CGRectMake(0, 0, size.width, size.height));
///创建需要绘制的文字
NSMutableAttributedString *attStr = [[NSMutableAttributedString alloc] initWithString:self.asynText];
[attStr addAttribute:NSFontAttributeName value:self.asynFont range:NSMakeRange(0, self.asynText.length)];
[attStr addAttribute:NSBackgroundColorAttributeName value:self.asynBGColor range:NSMakeRange(0, self.asynText.length)];
///根据attStr生成CTFramesetterRef
CTFramesetterRef frameSetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attStr);
CTFrameRef frame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, attStr.length), path, NULL);
///将frame的内容绘制到content中
CTFrameDraw(frame, context);
UIImage *getImg = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
///子线程完成工作, 切换到主线程展示
dispatch_async(dispatch_get_main_queue(), ^{
self.layer.contents = (__bridge id)getImg.CGImage;
});
});
}
网络层的优化:
减少DNS请求,使用HttpDNS获取原始ip地址进行请求,在header请求头中增加host字段,指定为原始请求地址
数据传输使用gzip
合并请求,减少请求并发数(埋点SDK,crash日志收集)
使用断点续传,否则网络不稳定时可能多次传输相同的内容
结合ETag 和 Last-Modified 减少数据重复传输
网络请求本地缓存
避免频繁发起请求
请求失败缓存后重发请求
2G、3G、4G、wifi下设置不同的超时时间
弱网环境下,减少并发请求
http2本身支持的长连接,多路复用机制
网络不可用时,不要进行网络请求
上传和下载大数据时,一次下载多点
app优化篇的更多相关文章
- 百度APP移动端网络深度优化实践分享(二):网络连接优化篇
本文由百度技术团队“蔡锐”原创发表于“百度App技术”公众号,原题为<百度App网络深度优化系列<二>连接优化>,感谢原作者的无私分享. 一.前言 在<百度APP移动端网 ...
- 百度APP移动端网络深度优化实践分享(一):DNS优化篇
本文由百度技术团队“蔡锐”原创发表于“百度App技术”公众号,原题为<百度App网络深度优化系列<一>DNS优化>,感谢原作者的无私分享. 一.前言 网络优化是客户端几大技术方 ...
- 百度APP移动端网络深度优化实践分享(三):移动端弱网优化篇
本文由百度技术团队“蔡锐”原创发表于“百度App技术”公众号,原题为<百度App网络深度优化系列<三>弱网优化>,感谢原作者的无私分享. 一.前言 网络优化解决的核心问题有三个 ...
- 【转】Android性能优化之布局优化篇
转自:http://blog.csdn.net/feiduclear_up/article/details/46670433 Android性能优化之布局优化篇 分类: andorid 开发2015 ...
- 【HELLO WAKA】WAKA iOS客户端 之一 APP分析篇
由于后续篇幅比较大,所以调整了内容结构. 全系列 [HELLO WAKA]WAKA iOS客户端 之一 APP分析篇 [HELLO WAKA]WAKA iOS客户端 之二 架构设计与实现篇 [HELL ...
- HTML5进阶(三)HBuilder实现软件自动升级(优化篇)
HBuilder实现软件自动升级(优化篇) 前言 受前篇博客<HTML5进阶(二)HBuilder实现软件自动升级>(点击查看详情)的影响,测试过程中发现APP自动更新还是存在问题,第一次 ...
- Hybrid APP基础篇(二)->Native、Hybrid、React Native、Web App方案的分析比较
说明 Native.Hybrid.React.Web App方案的分析比较 目录 前言 参考来源 前置技术要求 楔子 几种APP开发模式 概述 Native App Web App Hybrid Ap ...
- Android App优化之ANR详解
引言 背景:Android App优化, 要怎么做? Android App优化之性能分析工具 Android App优化之提升你的App启动速度之理论基础 Android App优化之提升你的App ...
- Hybrid APP基础篇(四)->JSBridge的原理
说明 JSBridge实现原理 目录 前言 参考来源 前置技术要求 楔子 原理概述 简介 url scheme介绍 实现流程 实现思路 第一步:设计出一个Native与JS交互的全局桥对象 第二步:J ...
随机推荐
- 从yield 到yield from再到python协程
yield 关键字 def fib(): a, b = 0, 1 while 1: yield b a, b = b, a+b yield 是在:PEP 255 -- Simple Generator ...
- Android recovery支持adb shell
Android recovery支持adb shell 近期开发过程注意到recovery不支持adb shell.为了便于调试方便,决定添加此功能. 刚開始我们採用的是user版本号系统,进入rec ...
- 使用Node.js的Express框架进行文件上传
我们先创建一个Express项目,要使用文件上传的功能还需要下载multer模块. npm install --save multer 下面我们在public文件夹下创建upload.html,内容如 ...
- pip 安装出现超时问题的解决
pip 安装出现超时问题的解决 我们在用默认的pip源进行安装python库时,会出现超时问题下载不了,如下图显示所示: 那么我们应该如何解决呢? 方法: 在自己电脑的 C:\Users\yanji ...
- centos7下使用docker安装nginx
需要环境docker,此处不做介绍. 1. docker拉取官方nginx镜像 docker pull nginx 2. 等待下载完成后,我们就可以在本地镜像列表里查到 REPOSITORY 为 ng ...
- Angular4学习笔记-目录汇总
Angular4学习笔记(一)-环境搭建 Angular4学习笔记(二)-在WebStorm中启动项目 Angular4学习笔记(三)- 路由 Angular4学习笔记(四)- 依赖注入 Angula ...
- Android8 自定义广播接收不到的问题
最近在用安卓广播的时候,按照流程进行操作,可是不管怎样都没有出现我接受的广播,网上查阅资料以后,发现在Android8中,如果是静态注册广播,需要在action中保留原来的静态广播,加入Compone ...
- css布局 - 工作中常见的两栏布局案例及分析
突然想到要整理这么一篇平时工作中相当常见但是我们又很忽视的布局的多种处理方法.临时就在我经常浏览的网站上抓的相对应的截图.(以后看到其他类型的我再补充) 既然截了图,咱们就直接看人家使用的布局方式,毕 ...
- express中间件--Morgan 日志记录
Morgan是一个node.js关于http请求的日志中间件 安装模块 npm install morgan --save #保存到package.json的依赖列表1使用方法 在终端打印日志...v ...
- python开发工具
要用到爬虫,网上推荐crapy,自己在pycharm上没有安装成功,于是使用anaconda,但是在gui界面安装crapy总是失败,且没有提示信息.于是使用命令行的方式,提示PermissionEr ...