首先,开发过程中,遇到过的内存的问题
1、self被delegate强引用了,导致内存不被释放。
2、imageNamed读取图片的方法,会缓存在内存中,所以较大的图片,还是用imageWithContentsOfFile。
3、block里没有使用弱引用self,导致一直持有self得不到释放。
一、内存优化
1、多使用懒加载:不要一次创建所有的subview,而是当需要时才创建,当它们完成了使命,把他们放进一个可重用的队列中,避免了不划算的内存分配。
2、使用复用:内存上对对象的复用,UITableView就是例子。另外,一些objects的初始化很慢,比如NSDateFormatter和NSCalendar,想要避免使用这个对象的瓶颈就需要重用他们,可以通过添加属性到你的class里或者创建静态变量来实现。
3、使用xib和storyboard布局注意简洁化:因为加载一个xib的时候所有内容都被放在了内存里,包括任何图片。尝试为每个Controller配置一个单独的xib,尽可能把一个View Controller的view层次结构分散到单独的xib中去。如果有一个不会即刻用到的view,你这就是在浪费宝贵的内存资源了。StoryBoard中不允许有单个view的存在,因此很多时候我们需要借助于单个的xib来自定义UI。
4、选择正确的数据结构:精心选择的数据结构可以带来更高的运行或者存储效率。
Arrays: 有序的一组值。使用index查询很快,使用value查表很慢,插入/删除很慢。
Dictionaries: 存储键值对,用键来查找比较快。
Sets: 无序的一组值,用值来查找很快,插入/删除很快。
5、由于后台运行的原因,导致的写代码时要注意的:由于在后台时,为了减少程序占用的内存,系统会自动在回收一些系统帮助你开辟的内存。
所以:
a.尽量减少内存的使用。当内存不足时,iOS将kill那些消耗内存最多的 App。
b.释放所有的共享资源,比如 Calendar 与 Address book。当应用程序进入后台时,如果它还在使用或没有释放共享资源,iOS会立即kill掉该应用程序。
c.对于图片对象、可以重新加载的大的视频或数据文件和任何没用而且可以轻易创建的对象应该尽快的去掉强引用。
d.正确处理App生命周期事件。当进入后台时,应该保持应用程序数据,以便回到前台时能够恢复。当进入 inactive 状态时,应该暂停当前的业务流。iOS运行App在后台运行的时间有限,因此后台代码不应该执行非常耗时的任务,可能的话就使用多线程。当进入后台时,iOS会保存当前App的一个快照,以便之后在合适的时候(装载view和数据时)呈现给用户以提高用户体验,因此在进入后台时,应该避免在屏幕上呈现用户信息,以免泄露用户个人资料。
e.不要更新UI或者执行大量消耗CPU或电池的代码。进入后台之后,不应该执行不必要的任务,不要执行 OpenGL ES 调用,应取消 Bonjour 相关的服务,正确处理网络链接失败,避免更新 UI,清除所有的警告或其他弹出对话框。
f.在后台时正确响应系统变化。 如:
设备旋转消息 UIDeviceOrientationDidChangeNotification
重要的时间变化(新的一天开始或时区变化)UIApplicationSignificantTimeChangeNotification
电池变化 UIDeviceBatteryLevelDidChangeNotification 和 UIDeviceBatteryStateDidChangeNotification
用户默认设置变化 NSUserDefaultsDidChangeNotification
本地化语言变化 NSCurrentLocaleDidChangeNotification 等。
g.保存用户数据或状态信息,所有没写到磁盘的文件或信息,在进入后台时,最好都写到磁盘去,因为程序可能在后台被杀死。
applicationDidEnterBackgound: 方法有大概5秒的时间让你完成自己的任务。如果超过时间还有未完成的任务,你的程序就会被终止而且从内存中清除。如果还需要长时间的运行任务,可以调用 beginBackgroundTaskWithExpirationHandler方法去请求后台运行时间和启动线程来运行长时间运行的任务。
6、处理内存警告:iOS下每个app可用的内存是被限制的,如果一个app使用的内存超过了这个阀值,则系统会向该app发送Memory Warning消息。收到消息后,app必须尽可能多的释放一些不必要的内存,否则OS会关闭app。最佳方式是移除缓存、图片对象和其他一些可以重创建对象的强引用。
处理内存警告具体方法如下:
-(void)didReceiveMemoryWarning{[superdidReceiveMemoryWarning];//即使没有显示在window上,也不会自动的将self.view释放。// 保证是在6.0下使用的,6.0以前屏蔽以下代码,否则会在下面使用self.view时自动加载viewDidUnLoadif([[UIDevicecurrentDevice].systemVersion floatValue] >=6.0) {//需要注意的是self.isViewLoaded是必不可少的,其他方式访问视图会导致它加载if(self.isViewLoaded && !self.view.window)// 是否是正在使用的视图{self.view =nil;// 目的是再次进入时能够重新加载调用viewDidLoad函数。}}}
二、缓存优化:
1、iOS缓存优化
尽量 cache 那些可重复利用的对象,缓存那些不大可能改变但是需要经常读取的东西,比如table cell、date/number formatters、远端服务器的响应、图片、甚至计算结果(UITableView的行高)等。
2、NSURLConnection
NSURLConnection默认会缓存资源在内存或者存储中根据它所加载的HTTP Headers。
3、NSURLCache
iOS中缓存技术用到了NSURLCache类。
4、NSCache
NSCache是苹果官方提供的缓存类,NSCache是线程安全的,在多线程操作中,不需要对Cache加锁。NSCache的Key只是对对象的strong引用,对象不需要实现NSCopying协议,NSCache也不会像NSDictionary一样复制对象。
5、两种图片加载方式
常见的从bundle中加载图片的方式有两种,一个是用imageNamed,二是用imageWithContentsOfFile。
imageNamed的优点是当加载时会缓存图片,这个方法用,如果图片存在的话,一个指定的名字在系统缓存中查找并返回一个图片对;如果缓存中没有找到相应的图片,这个方法从指定的文档中加载然后缓存并返回这个对象。而imageWithContentsOfFile仅加载图片。如果你要加载一个大图片而且是一次性使用,那么就没必要缓存这个图片,用imageWithContentsOfFile足矣,这样不会浪费内存来缓存它。然而,在图片反复重用的情况下imageNamed是一个好得多的选择。
三、CPU缓存解析
四、iOS存储优化
使用最合适的数据存储方式
NSUerDefaults:便捷,但是只适用于小数据;
XML, JSON, 或者 plist:能处理大数据,但需要读取整个文件到内存里去解析,浪费资源;
NSCoding存档:也需要读取文件,具有同上的问题;
SQL数据库或者 Core Data:使用这些技术比较好,用特定的查询语句就能只加载需要的对象。
1)、Core Data使用分析:
a.概念:Core Date是对SQLite的封装,提供了更高级的数据持久化解决方案。Core Data是完全独立于任何UI层级的框架,它是作为模型层框架被设计出来的。在对数据库操作时,不需要使用sql语句,是一种ORM(“对象关系映射”)的数据库操作方式,ORM将关系数据库中的表,转化为程序中的对象,但实际上是对数据中的数据进行操作,按照面向对象的思想,使用实体模型来操作数据库。使用Core Data进行数据库存取不需要手动创建数据库,创建数据库的过程完全由Core Data框架自动完成,开发者需要做的就是把模型创建起来,Core Data实际上是将数据库的创建、表的创建、对象和表的转换等操作封装起来,以简化我们的操作。如果模型发生了变化,可以选择重新生成实体类文件,但是自动生成的数据库并不会自动更新,需要考虑重新生成数据库,并把之前数据库中数据进行移植。
b.优势:简化操作。(特别是在App升级之后数据库字段或者表有更改会导致crash)
c.劣势:不支持跨平台使用。
2)、SQL数据库使用分析:
a.概念:Core Data代表一个对象的graph model(图表模型),SQLite就是一个DBMS,也更加底层。使用SQLite,可以用FMDB这个库来简化SQLite的操作,节省了了解SQLite的C API的时间。
b.优势:支持跨平台使用
c.劣势:相对Core Data操作复杂
五、网络请求优化
1)、对请求压缩:减小文档的一个方式就是在服务端和你的app中打开gzip,这对于文字这种能有更高压缩率的数据来说会有更显著的效用。iOS已经在NSURLConnection中默认支持了gzip压缩,当然AFNetworking这些基于它的框架亦然。
2)、对数据压缩:Web浏览器对请求压缩的支持并不太好,因为浏览器不知道目标服务器是否能够支持对请求的解压缩。所以Base64预先压缩数据是个很好的方法,比如以Base64格式上传JPEG文件,那么可以对Base64数据进行压缩,相较于未压缩的Base64数据,压缩后的数据体积会降低30%左右。
3)、选择合适的传输数据的方案:压缩模式的效率在很大程序上取决于待压缩的数据,不过通常情况下JSON都是一种更为高效的模式。
4)、降低请求延迟:有两项最佳实践:
a.在单个TCP连接上发送HTTP请求,以管道的形式发送HTTP请求,从而优化全双工TCP连接的使用。Apache和IIS都支持管道,无需任何额外的配置。
b.通过HTTP缓存机制的基本原理,在iOS应用中利用这些规则,可以在本地缓存内容以避免不必要的网络流量。如我们上面提到的NSURLCache、NSCache等。
5)、另外,优化网络请求的一环是DNS解析:因为客户端app的请求第一步都是DNS解析,但由于cache的存在使得大部分的解析请求并不会产生任何延迟。所以,如果能直接跳过DNS解析这一步,当然能提升网络性能了。
a.一种方法是使用DNS映射。
b.另外就是直接用ip请求数据。DNS解析请求简单来说,就是输入一个域名,输出一个ip地址。做自己的映射机制也就是客户端本地维护这样一个映射文件,只不过这个映射文件需要能从服务器更新,还要做一些容错处理。