iOS 项目优化

746 阅读6分钟

项目结构(基本结构)

项目本身首先划分功能区以PageCoreApp划分

  • Page存储应用的模块,包含首页个人中心等,每个模块下再以ControllerViewModel划分
  • Core 存储着一些与项目业务、界面无关的类,包括分类宏定义封装的请求基类
  • App则存储着一些与项目相关的类,包括APIBase基类

应用包瘦身

1、首先找出项目中未使用的图片:

这里使用了python脚本 脚本地址 找出项目中未使用的图片,结果不是非常准确,但是可以自行判断(存在图片使用是根据服务端返回显示的情况等)

2、图片无损压缩

这里使用工具 ImageOptim ,点击链接下载 将项目图片拖入优化即可 

3、代码瘦身

这里推荐使用LinkMap,可以知道项目中各个类的大小,以权衡是否有替换方案

4、 使用 fui 找到应用中未使用的类

安装fui

sudo gem install fui -n /usr/local/bin

到项目中使用

fui find

二、项目性能优化

内存

使用instruments leaks 检测 打开:

  1. Product -> Profile -> Leaks
  2. 点击CellTree、下方筛选
  3. 定位泄漏代码,修改

工具只是辅助你寻找泄漏的地方,具体是否泄漏还需要自行判断

卡顿

在性能优化中一个最具参考价值的属性是FPS: 全称Frames Per Second,其实就是屏幕刷新率,苹果的iphone推荐的刷新率是60Hz,也就是说GPU每秒钟刷新屏幕60次,这每刷新一次就是一帧frame,FPS也就是每秒钟刷新多少帧画面。静止不变的页面FPS值是0,这个值是没有参考意义的,只有当页面在执行动画或者滑动的时候,FPS值才具有参考价值,FPS值的大小体现了页面的流畅程度高低,当低于45的时候卡顿会比较明显。

这里使用Core Animation来检测,注:需使用真机

卡顿优化:

1、Color Blended Layers (图层混合)

这个选项是检测哪里发生了图层混合,先介绍一下什么是图层混合?很多情况下,界面都是会出现多个UI控件叠加的情况,如果有透明或者半透明的控件,那么GPU会去计算这些这些layer最终的显示的颜色,也就是我们肉眼所看到的效果。例如一个上层Veiw颜色是绿色RGB(0,255,0),下层又放了一个View颜色是红色RGB(0,0,255),透明度是50%,那么最终显示到我们眼前的颜色是蓝色RGB(0,127.5,127.5)。这个计算过程会消耗一定的GPU资源损耗性能。如果我们把上层的绿色View改为不透明, 那么GPU就不用耗费资源计算,直接显示绿色。 如果出现图层混合了,打开Color Blended Layers选项,那块区域会显示红色,所以我们调试的目的就是将红色区域消减的越少越好。那么如何减少红色区域的出现呢?只要设置控件不透明即可。

  1. 设置opaque 属性为true。
  2. 给View设置一个不透明的颜色,没有特殊需要设置白色即可。

eg:

运行应用 在模拟器中找到:

Color Blended Layers

TIP:当UILabel的内容是中文,需要添加一句 label.layer.masksToBounds = YES,因为当UILabel的内容为中文时,label实际渲染区域要大于label的size,最外层多了一个sublayer,如果不设置第二行label的边缘外层 会出现图层混合的红色,因此需要在label内容是中文的情况下加第二句。
单独使用label.layer.masksToBounds = YES是不会发生离屏渲染的

注:xib 也可以直接设置 masksToBounds 在控件的:

xib.masksToBounds

2、Color Misaligned Images(图片大小)

这个选项可以帮助我们查看图片大小是否正确显示。如果image size和imageView size不匹配,image会出现黄色。要尽可能的减少黄色的出现,因为image size与imageView size不匹配,会消耗资源压缩图片。 选择:  如果图片出现黄色,可自行将图片压缩至ImageView大小

image.png

3、Color Offscreen-Rendered Yellow(离屏渲染)

离屏渲染Off-Screen Rendering 指的是GPU在当前屏幕缓冲区以外新开辟一个缓冲区进行渲染操作。还有另外一种屏幕渲染方式-当前屏幕渲染On-Screen Rendering ,指的是GPU的渲染操作是在当前用于显示的屏幕缓冲区中进行。
离屏渲染会先在屏幕外创建新缓冲区,离屏渲染结束后,再从离屏切到当前屏幕, 把离屏的渲染结果显示到当前屏幕上,这个上下文切换的过程是非常消耗性能的,实际开发中尽可能避免离屏渲染。 触发离屏渲染Offscreen rendering的行为:

  • drawRect:方法
  • layer.shadow
  • layer.allowsGroupOpacity or layer.allowsEdgeAntialiasing
  • layer.shouldRasterize
  • layer.mask
  • layer.masksToBounds && layer.cornerRadius

eg:

运行项目,打开:

Color Off-screen Rendered

官方的优化

  1. iOS 9.0 之前UIimageView和UIButton设置圆角都会触发离屏渲染。
  2. iOS 9.0 之后UIButton设置圆角会触发离屏渲染,而UIImageView里png图片设置圆角不会触发离屏渲染,但是设置其他阴影效果之类的还是会触发离屏渲染。

开发者的优化

方法一:UIBezierPath和CAShapeLayer
方法二:利用CoreGraphics画一个圆形上下文,然后把图片绘制上去,得到一个圆形的图片
方法三:使用贝塞尔曲线UIBezierPath和Core Graphics框架画出一个圆角
方法四:AsyncDisplayKit(异步绘制框架)

点击查看AsyncDisplayKit项目

方法五:程序员+设计师
  • 直接让设计师把图片切成圆角进行显示

  • 尽量使用不包含透明(alpha)通道的图片资源

  • 用户上传图片,可以让服务端处理圆角

三、使用RunTime 尽量避免 crash

程序运行中难免会出现崩溃,这里我们可以使用runtime尽量避免一些常见的崩溃错误: #####eg: 给NSArray 替换 objectAtIndex:方法

+ (void)load {
    [NSClassFromString(@"__NSArrayI") swapMethod:@selector(objectAtIndex:) currentMethod:@selector(mq_objectAtIndex:)];
}

- (id)mq_objectAtIndex:(NSUInteger)index
{
    if (index >= [self count])
    {
        return nil;
    }
    return [self mq_objectAtIndex:index];
}

+ (void)swapMethod:(SEL)originMethod currentMethod:(SEL)currentMethod;
{
    Method firstMethod = class_getInstanceMethod(self, originMethod);
    Method secondMethod = class_getInstanceMethod(self, currentMethod);
    method_exchangeImplementations(firstMethod, secondMethod);
}
复制代码

Load方法替换 objectAtIndexmq_objectAtIndex ,当调用objectAtIndex时会走到mq_objectAtIndex,判断是否越界,以此来预防数组越界的crash 其他类像NSDictionary、NSString也可以自行添加

结语

iOS项目优化还有挺多方面的,包括电池优化、启动优化等等