iOS 优化实例
一、接口请求优化
在工程项目中,多个一级界面包含状态,如:服务入口的动态配置,未读消息数量,图片文字等,因此产品设计要每次切换 tab 时都请求数据,及时的更新页面状态。在实际开发中,频繁的调用接口,频繁的刷新界面显然是影响用户体验的,所以需要进行优化,优化的思路有以下几点:
- 使用 loading + 默认灰色矩形视图;
每隔 15s 以上才请求一次,防止频繁触发请求
@property (nonatomic, assign) CFTimeInterval lastTi;
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
CFTimeInterval nowTi = CACurrentMediaTime();
if (self.lastTi <= 0 || nowTi - self.lastTi > 15) {
[self makeRequestAction];
self.lastTi = nowTi;
}
}
- (void)makeRequestAction
{
// 接口请求
}
CACurrentMediaTime() 在退到后台、手动修改设备时间后没有影响。
对数据进行判断,数据没有更新不需要刷新界面。这里要注意,存储的是不是字符串,而是字符串的 hash 值,因为长度比较小。
@property (nonatomic, assign) NSUInteger compareHash; // 判断列表数据是否更新
{
NSUInteger hash = [data.mainTools componentsJoinedByString:@""].hash;
if (self.compareHash == hash) {
return;
}
self.compareHash = hash;
// 更新界面
}
这里的策略还是存在点问题:
- 不能处理好未读标识。比如当进入子界面详情时,这里需要更新未读状态,但因为 15s 的限制,而不能及时刷新;
二、界面优化
使用 Debug -> View Debugging -> Rendering 中的界面渲染选项,进行界面优化

cell 滚动停止时加载
三、资源加载优化
图片加载
imageNamed:
利用它可以方便加载资源图片。用 imageNamed 的方式加载时,会把图像数据根据它的名字缓存在系统内存中,以提高 imageNamed 方法获得相同图片的 image 对象的性能。即使生成的对象被 autoReleasePool 释放了,这份缓存也不释放。而且没有明确的释放方法。如果图像比较大,或者图像比较多,用这种方式会消耗很大的内存。
优点:加载图片速度快;
缺点:耗内存大,适用于小图片并且会被频繁读取的图片。imageWithContentsOfFile:
加载的图片是不会缓存的。得到的对象时 autoRelease 的,当 autoReleasePool 释放时才释放。
优点:图片数据不缓存,节省内存;
缺点:加载图片速度相对慢,每次读取图片都要从路径下寻找并解析图片数据。适用于会用到的图片数据不大,且不经常用到的。imageNamed: 加载会缓存在内存中,对于常用的图片可以放在 asset 里,不常用的图片放在 bundle 的路径下通过 imageWithContentsOfFile: 获取图片资源。
initWithContentsOfFile:
一般用在封面等图比较大的地方。适用于大图片,且不经常要用的图片。
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(4 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
for (int i = 0; i < 100000; i++) {
self.loadImageView.image = [UIImage imageNamed:@"icon"];
//self.loadImageView.image = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"icon" ofType:@"png"]];
}
});
imageNamed:


imageWithContentsOfFile:


在有缓存的情况下,即使运行 100000 次,也不会等待很久,而 imageWithContentsOfFile: 会等待很久,且内存持续增长。
UITableView 中使用 imageNamed: 加载图片,频繁上下滑动时 CPU 耗时不断增长。
原本期望 imageNamed: 创建了缓存的,不应该持续耗费 cpu 时间,结果却耗费了 6-700ms,多处合起来有几秒。
优化思路是自己使用 NSDictionary 或 NSCache 存储 images,使用时根据 key 来获取。
// .h 文件
FOUNDATION_EXTERN NSString * kAPlaceholderImageKey;
FOUNDATION_EXTERN NSString * kBPlaceholderImageKey;
- (UIImage *)imageForKey:(NSString *)placeholderImageKey;
// .m 文件
NSString * kAPlaceholderImageKey = @"APlaceholderImageKey";
NSString * kBPlaceholderImageKey = @"BPlaceholderImageKey";
- (UIImage *)imageForKey:(NSString *)placeholderImageKey
{
return [self.imageCache objectForKey:placeholderImageKey];
}
/**
* @brief 缓存 cell 中需要重复使用的图片
*/
- (NSCache *)imageCache
{
if (_imageCache == nil) {
_imageCache = [[NSCache alloc] init];
[_imageCache setObject:[UIImage imageNamed:@"1"] forKey:kAPlaceholderImageKey];
[_imageCache setObject:[UIImage imageNamed:@"2"] forKey:kBPlaceholderImageKey];
}
return _imageCache;
}
四、启动速度优化
Total pre-main time: 617.58 milliseconds (100.0%)
dylib loading time: 472.75 milliseconds (76.5%)
rebase/binding time: 27.01 milliseconds (4.3%)
ObjC setup time: 28.90 milliseconds (4.6%)
initializer time: 88.76 milliseconds (14.3%)
slowest intializers :
libSystem.B.dylib : 8.81 milliseconds (1.4%)
libMainThreadChecker.dylib : 14.42 milliseconds (2.3%)
AFNetworking : 18.43 milliseconds (2.9%)
Realm : 20.98 milliseconds (3.3%)
CYKJBasicModule : 12.96 milliseconds (2.0%)
删除不需要的三方库
+load -> +initialize
注意有的功能需要写在 +load 方法。可以改为 +initialize 后,用断点看看是否被调用。
动态库 -> 静态库
如果 Podfile 中使用 use_frameworks!,那么第三方库都是以动态库的方式添加到工程中,动态库在启动阶段由 dyld 加载,静态库是运行时加载,所以为了减少 dylib loading time,可以减少工程中的动态库。
内存
iOS微信内存监控
包体积
- 删除无用代码和资源文件
- 压缩资源文件
- 动态下发 zip 包
内置 zip 压缩包
- 首次启动需要解压,会牺牲首次使用的启动速度
32 位、64 位双架构问题
- 将引擎 zip 包置于 app 动态库内来规避这个问题,因为 AppStore 会针对动态库自动实现分架构下发
- 需要注意下载失败、解压失败的问题。
iOS 优化实例的更多相关文章
- MySQL优化实例
这周就要从泰笛离职了,在公司内部的wiki上,根据公司实际的项目,写了一些mysql的优化方法,供小组里的小伙伴参考下,没想到大家的热情很高,还专门搞了个ppt讲解了一下. 举了三个大家很容易犯错的地 ...
- mysql 优化实例之索引创建
mysql 优化实例之索引创建 优化前: pt-query-degist分析结果: # Query 23: 0.00 QPS, 0.00x concurrency, ID 0x78761E301CC7 ...
- mysql sql优化实例
mysql sql优化实例 优化前: pt-query-degist分析结果: # Query 3: 0.00 QPS, 0.00x concurrency, ID 0xDC6E62FA021C85B ...
- (转载)Android项目实战(二十八):使用Zxing实现二维码及优化实例
Android项目实战(二十八):使用Zxing实现二维码及优化实例 作者:听着music睡 字体:[增加 减小] 类型:转载 时间:2016-11-21我要评论 这篇文章主要介绍了Android项目 ...
- iOS优化内存方法推荐
1. 用ARC管理内存 ARC(Automatic ReferenceCounting, 自动引用计数)和iOS5一起发布,它避免了最常见的也就是经常是由于我们忘记释放内存所造成的内存泄露.它自动为你 ...
- PNG与iOS优化选项
从App Store下载到的每一枚App最初都是一只IPA文件(其实是zip格式,内含特定规则的文件夹组织方式).但当作zip解开之后会发现里面很多的PNG文件看不了,这是因为在这些PNG图像都已被i ...
- mysql sql优化实例1(force index使用)
今天和运维同学一块查找mysql慢查询日志,发现了如下一条sql: SELECT sum(`android` + ios) total,pictureid,title,add_time FROM `j ...
- iOS 优化方案浅析
本文转载至 http://mobile.51cto.com/iphone-413256.htm Windows独特的注册表机制以及复杂的进程.内存管理,给了很多PC“优化”类软件极大的机遇,比如奇虎3 ...
- Android ListView性能优化实例讲解
前言: 对于ListView,大家绝对都不会陌生,只要是做过Android开发的人,哪有不用ListView的呢? 只要是用过ListView的人,哪有不关心对它性能优化的呢? 关于如何对ListVi ...
随机推荐
- JMeter-接口测试之数据驱动
前言 之前我们的用例数据都是配置在Http 请求中,每次需要增加,修改用例都需要打开 jmeter 重新编辑,当用例越来越多的时候,用例维护起来就越来越麻烦,有没有好的方法来解决这种情况呢?我们可以将 ...
- JUC常用同步工具类——CountDownLatch,CyclicBarrier,Semaphore
在 JUC 下包含了一些常用的同步工具类,今天就来详细介绍一下,CountDownLatch,CyclicBarrier,Semaphore 的使用方法以及它们之间的区别. 一.CountDownLa ...
- Nginx之反向代理配置(二)
前文我们聊了Nginx的防盗链.反向代理以及开启nginx代理缓存,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/12417130.html:今天我们继续说ng ...
- 这些Zepto中实用的方法集
前言 时间过得可真快,转眼间2017年已去大半有余,你就说吓不吓人,这一年你成长了多少,是否荒度了很多时光,亦或者天天向上,收获满满.今天主要写一些看Zepto基础模块时,比较实用的部分内部方法,在我 ...
- 关于integer overflow错误
前端突然报了integer overflow错误,int类型溢出也就是数字超过了int类型,一看很懵逼,查看后台日期发现是在Math.toIntExact()方法报错 那么我们看下方法内部代码: /* ...
- ES6拓展的对象功能
前言:因为之前看过很多的博客啊,书籍啊但是最后都雁过无痕,再问我基本没什么印象,所以就迫使自己看书的时候记点笔记,因为懒得写字[捂脸],现在是打字比写字要快好多,所以就写博客吧! ES6规范明确定义了 ...
- SpringBoot2 整合ElasticJob框架,定制化管理流程
本文源码:GitHub·点这里 || GitEE·点这里 一.ElasticJob简介 1.定时任务 在前面的文章中,说过QuartJob这个定时任务,被广泛应用的定时任务标准.但Quartz核心点在 ...
- 硬核数据结构,让你从B树理解到B+树
本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是周五分布式系统的第八篇文章,核心内容是B+树的原理. 今天的文章是上周B树的延伸,所以新关注的或者是有所遗忘的同学建议先从下方链接回顾 ...
- Django 中自定义用户模型及集成认证授权功能总结
1. 概述 Django 中的 django.contrib.auth 应用提供了完整的用户及认证授权功能. Django 官方推荐基于内置 User 数据模型创建新的自定义用户模型,方便添加 bir ...
- python之 filter
filter的语法:filter(函数名字,可迭代的变量) 其实filter就是一个“过滤器”:把[可迭代的变量]中的值,挨个地传给函数进行处理,那些使得函数的返回值为True的变量组成的迭代器对象就 ...