1.使用arc管理内存,避免内存泄漏。
2.给UITableViewCells,UICollectionViewCells设置reuseIdentifier。利用重用机制
3.不要设置透明的视图,会引发离屏渲染。
⚠️:其他会引发离屏渲染的操作:光栅化,设置mask遮罩,设置透明视图,设置阴影等。
4.尽量不要使用过于复杂的xib
因为一旦加载了xib就会把这个xib里所有的内容都放到内存里,占用内存资源。storyboard是不会的,在需要的时候才会去实例化。在有些情况下不得不使用xib,比如说要设计一个高度重用的UIView。
5.不要阻塞主线程
阻塞了主线程很有可能造成界面卡死,非常影响性能。UIKit在主线程做了很多的事情,比如说视图的绘制,事件的响应,输入等等,所以不要把其他的耗时操作放到主线程去执行了。
⚠️:在主线程更新UI的最根本原因是为了保证线程安全,因为UIKit这个框架本身不是线程安全的,如果对这么大的一个框架里的每一个操作都保证线程安全就会非常影响性能,所以如果同时在多个线程里进行UI操作就可能导致线程不安全,产生各种各样的问题,因此必须在主线程更新UI。
6.不要在运行过程中缩放图片
也就是说应该在后台线程缩放图片,让图片的大小和控件的大小一样大,在运行的时候直接设置图片。
7.选择正确的数据结构去存储数据
比如说用index查找数组中的数据很快,但是插入删除就很慢。
8.合理利用懒加载
等到需要显示某一个控件的时候再去创建他,这样就避免了一下子创建很多没有使用到的控件,占用内存。
9.合理利用缓存
缓存一些不常改变的内容,比如缓存登陆注册界面,图片缓存等等。实现缓存时,我们应优先选择NSCache去存储缓存内容,而不是选择NSDictionary。
⚠️:下面重点说一下NSCache和NSDictionary之间的区别和联系。
1.NSCache在系统发出内存警告时会自动删减缓存,并且从最久未使用的对象开始删减。
2.NSCache是线程安全的,开发者在不需要编写加锁代码的前提下就可以在多个线程里同时访问NSCache。
⚠️:对于缓存来说线程安全是很重要的,因为我们可能在一个线程里查找缓存,如果查不到就要开始下载数据,下载完数据所执行的回调函数往往在另一个后台线程执行,这个时候就在另一个线程里写入数据,因此缓存必须是线程安全的。
3.缓存中有几个属性,开销值,缓存对象总数countLimit,缓存对象总开销totalCostLimit。当我们要缓存一个对象的时候,可以判断缓存对象的开销值,如果加入了这个对象导致缓存对象总数或者对象总开销超过了最大值,那么这个时候就要根据需求删减缓存。
4.读取缓存和向缓存中写入数据的方式和NSDictionary非常相似。
[_cache objectForKey:url];
[_cache setObject:data forKey:url cost:data.length];还可以设置cost值
⚠️:我们不能滥用缓存,只有那些获取起来比较耗时的数据才值得被放入缓存,如果是那种经常改变或者获取很方便的数据是不应该放入缓存的。
10.处理内存警告
什么时候会收到内存警告呢?程序运行过程中,当程序占用的内存超过了一个数值以后,系统就会向程序发出内存警告,如果没有对内存警告进行处理,就会导致程序crash。
处理内存警告的顺序:发生内存警告的时候首先调用appDelegate中的方法
-(void)applicationDidReceiveMemoryWarning:(UIApplication *)application{}
然后调用各个子控制器的方法
-(void)didReceiveMemoryWarning{}
具体的处理内存警告的代码应该放在各个子控制器去处理,我们可以在didReceiveMemoryWarning方法中添加如下代码,来清空没有显示的view。
- (void)didReceiveMemoryWarning{
[superdidReceiveMemoryWarning];
if([self isViewLoaded] && self.view.window ==nil){ ⚠️:这个判断就是说这个view是不是已经被加载了isViewLoaded,并且判断这个view是不是没有被显示在屏幕上。
{self.view =nil;}//把这个视图置为nil,释放暂时不需要用到的内存,目的是再次进入时能够重新加载调用viewDidLoad函数。
}
看到有人说现在已经不需要在didReceiveMemoryWarning方法中做事了,如果程序在运行过程中发生了内存警告说明是代码有问题,比如说下载视频图片等大文件的时候全都加载到内存里,引起内存暴增。
1.如果使用了SDWebImage框架,使用如下代码,可以有效的减少内存:
[[SDImageCache sharedImageCache] setValue:nil forKey:@"memCache"];//清除内存中通过SDWebImage框架下载的图片,建议在收到内存警告时在调用
2.在后台压缩图片
3.加载图片时选择不同的方法:
imageNamed:这个方法在加载图片时会对图片进行缓存,适用于加载一些经常使用的小图片
imageWithContentsOfFile:仅加载图片,不会进行缓存,适用于加载一些不经常使用的大图片
4.占据大量内存的中间变量应该放到自动释放池中,比如说加载一百张图片,如果写在一个for循环里会导致内存暴增,而且因为一直没有退出循环不会释放自动释放池,所以就一直存在内存里。
tr5.用instrument工具检测内存泄漏等等。
11.选择正确的数据格式
通常我们获取和传递的数据格式有json和xml两种,下面重点学一下他们的区别。
JSON和XML的可读性都很强,易于理解。
JSON的编码难度更低,而XML的编码难度较高。
JSON易于解析,XML解析起来更复杂。
JSON比XML的速度快。
XML比JSON更强大,但是有些时候使用JSON会更快更方便。
XML的两种解析方式:SAX和DOM。
DOM是一次性把整个文件读取到内存然后解析。
SAX是从根节点开始一边读取一边解析文件,不会导致内存暴增,适用于读取大文件。
⚠️:这一条就体现了xml的优点,有些时候解析大文件就需要用xml。
12.加快app的启动时间
这个问题我打算单独写一个文章