转自 http://www.cocoachina.com/newbie/basic/2013/0522/6259.htmlhtml
在开发iOS应用程序时,让程序具备良好的性能是很是关键的。这也是用户所指望的,若是你的程序运行迟钝或缓慢,会招致用户的差评。然而因为iOS设备的局限性,有时候要想得到良好的性能,是很困难的。在开发过程当中,有许多事项须要记住,而且关于性能影响很容易就忘记。ios
本文收集了25个关于能够提高程序性能的提示和技巧,把性能优化技巧分为3个不一样的等级:初级、中级和高级git
初级github
在开发过程当中,下面这些初级技巧须要时刻注意:web
1.使用ARC进行内存管理
2.在适当的状况下使用reuseIdentifier
3.尽量将View设置为不透明(Opaque)
4.避免臃肿的XIBs
5.不要阻塞主线程数据库
6.让图片的大小跟UIImageView同样
7.选择正确的集合
8.使用GZIP压缩编程
1) 使用ARC进行内存管理json
ARC是在iOS 5中发布的,它解决了最多见的内存泄露问题——也是开发者最容易健忘的。ARC的全称是“Automatic Reference Counting”——自动引用计数,它会自动的在代码中作retain/release工做,开发者不用再手动处理。数组
下面是建立一个View通用的一些代码块:缓存
在上面代码结束的地方很容易会忘记调用release。不过当使用ARC时,ARC会在后台自动的帮你调用release。
ARC除了能避免内存泄露外,还有助于程序性能的提高:当程序中的对象再也不须要的时候,ARC会自动销毁对象。因此,你应该在工程中使用ARC。
下面是学习ARC的一些资源:
Tony Dahbura的如何在Cocos2D 2.X工程中使用ARC
若是你仍然不肯定ARC带来的好处,那么看一些这篇文章:8个关于ARC的神话——这可以让你相信你应该在工程中使用ARC!
值得注意的是,ARC并不能避免全部的内存泄露。使用ARC以后,工程中可能还会有内存泄露,不过引发这些内存泄露的主要缘由是:block,retain循环,对CoreFoundation对象(一般是C结构)管理不善,以及真的是代码没写好。
这里有一篇文章是介绍哪些问题是ARC不能解决的 — 以及如何处理这些问题。
2) 在适当的状况下使用reuseIdentifier
为了得到最佳性能,当在tableView:cellForRowAtIndexPath:方法中返回cell时,table view的数据源通常会重用UITableViewCell对象。table view维护着UITableViewCell对象的一个队列或者列表,这些数据源已经被标记为重用了。
若是没有使用reuseIdentifier会发生什么?若是你在程序中没有使用reuseIdentifier,table view每次显示一个row时,都会配置一个全新的cell。这实际上是一个很是消耗资源的操做,而且会影响程序中table view滚动的效率。
自iOS 6以来,你可能还但愿header和footer views,以及UICollectionView的cell和supplementary views。
为了使用reuseIdentifiers,在table view请求一个新的cell时,在数据源中调用下面的方法:
若是table view维护的UITableViewCell队列或列表中有可用的cell,则从队列从移除一个已经存在的cell,若是没有的话,就从以前注册的nib文件或类中建立一个新的cell。若是没有能够重用的cell,而且没有注册nib文件或类,tableview的dequeueReusableCellWithIdentifier:方法会返回一个nil。
3) 尽量将View设置为不透明(Opaque)
若是view是不透明的,那么应该将其opaque属性设置为YES。为何要这样作呢?这样设置可让系统以最优的方式来绘制view。opaque属性能够在Interface Builder或代码中设置。
苹果的官方文档对opaque属性有以下解释:
This property provides a hint to the drawing system as to how it should treat the view. If set to YES, the drawing system treats the view as fully opaque, which allows the drawing system to optimize some drawing operations and improve performance. If set to NO, the drawing system composites the view normally with other content. The default value of this property is YES.
(opaque属性提示绘制系统如何处理view。若是opaque设置为YES,绘图系统会将view看为彻底不透明,这样绘图系统就能够优化一些绘制操做以提高性能。若是设置为NO,那么绘图系统结合其它内容来处理view。默认状况下,这个属性是YES。)
若是屏幕是静止的,那么这个opaque属性的设置与否不是一个大问题。可是,若是view是嵌入到scroll view中的,或者是复杂动画的一部分,不将设置这个属性的话确定会影响程序的性能!能够经过模拟器的Debug\Color Blended Layers选项来查看哪些view没有设置为不透明。为了程序的性能,尽量的将view设置为不透明!
4) 避免臃肿的XIBs
在iOS 5中开始使用Storyboards,而且将替代XIBs。不过在有些状况下XIBs仍然有用。若是你的程序须要运行在装有iOS 5以前版本的设备上,或者要自定义可重用的view,那么是避免不了要使用XIBs的。
若是必需要使用XIBs的话,尽可能让XIBs文件简单。而且每一个view controller对于一个XIB文件,若是能够的话,把一个view controller的view不一样的层次单独分到一个XIBs文件中。
(注意:当把一个XIB文件加载到内存时,XIB文件中的全部内容都将被加载到内存中,包括图片。若是有一个view还不当即使用的话,就会形成内存的浪费。而这在storyboard中是不会发生的,由于storyboard还在须要的时候才实例化一个view controller。)
当加载XIB时,全部涉及到的图片都将被缓存,而且若是是开发的程序是针对OS X的话,声音文件也会被加载。苹果的官方文档这样说:
When you load a nib file that contains references to image or sound resources, the nib-loading code reads the actual image or sound file into memory and and caches it. In OS X, image and sound resources are stored in named caches so that you can access them later if needed. In iOS, only image resources are stored in named caches. To access images, you use the imageNamed: method of NSImage or UIImage, depending on your platform.
(当加载一个nib文件时,也会将nib文件涉及到的图片或声音资源加载到内存中,nib-loading代码会将实际的图片或声音文件读取到内存中,并一直缓存着。在OS X中,图片和声音资源都存储在命名缓存中,这样以后若是须要的话,能够对其进行访问。在iOS中,只有图片资源被存储到命名缓存中。要访问图片的话,使用NSImage或UIImage(根据不一样的系统)的imageNamed:方法便可。)
显然,在使用storyboard时也会发生相似的缓存操做;不过我没有找到相关内容的任何资料。想要学习storyboard的更多知识吗?能够看看Matthijs Hollemans写的iOS 5中:初级Storyboard Part 1和Part2。
5) 不要阻塞主线程
在主线程作全部任务的风险是:若是你的代码阻塞了主线程,那么程序将出现反应迟钝。这回招致用户在App Store上对程序的差评!
在执行I/O操做中,大多数状况下都会祖塞主线程,这些操做须要从读写外部资源,例如磁盘或者网络。
关于网络操做可使用NSURLConnection的以下方法,以异步的方式来执行:
或者使用第三方框架,例如AFNetworking。
若是你须要作一些其它类型开销很大的操做(例如执行一个时间密集型的计算或者对磁盘进行读写),那么就使用GCD(Grand Central Dispatch),或NSOperations 和 NSOperationQueues。
下面的代码是使用GCD的一个模板:
如上代码,为何在第一个dispatch_async里面还嵌套了一个dispatch_async呢?这是由于关于UIKit相关的代码须要在主线程里面执行。
能够看看Ray Wenderlich中的教程:iOS中多线程和GCD—初级,以及Soheil Azarpour的如何使用NSOperations和NSOperationQueues教程。
6) 让图片的大小跟UIImageView同样
若是是从远程服务中下载图片,有时候你控制不了图片的尺寸,或者在下载以前没法在服务器上进行图片的缩放。这种状况,当图片下载完以后,你能够手动进行图片的缩放——作好是在后台线程中!——而后再在UIImageView中使用缩放过的图片。
7) 选择正确的集合
8) 使用GZIP压缩
愈来愈多的程序依赖于外部数据,这些数据通常来自远程服务器或者其它的外部APIs。有时候你须要开发一个程序来下载一些数据,这些数据能够是XML,JSON,HTML或者其它一些文本格式。
问题是在移动设备上的网络是不肯定的。用户的设备可能在EDGE网络一分钟,而后接着又在3G网络中。无论在什么状况下,都不要让用户等待。
有一个能够优化的选择:使用GZIP对网络传输中的数据进行压缩,这样能够减少文件的大小,并加快下载的速度。压缩对于文本数据特别有用,由于文本具备很高的压缩比。
iOS中,若是使用NSURLConnection,那么默认状况下已经支持GZIP压缩了,而且基于NSURLConnection的框架页支持GZIP压缩,如AFNetworking。甚至有些云服务提供商已经提供发送经压缩过的响应内容,例如Google App Engine。
这里有一篇关于GZIP压缩很好的文章,介绍了如何在Apache活IIS服务器中开启支持GZIP压缩。
在性能优化时,当你碰到一些复杂的问题,应该注意和使用以下技巧:
9.重用和延迟加载View
10.缓存、缓存、缓存
11.考虑绘制
12.处理内存警告
13.重用花销很大的对象
14.使用Sprite Sheets
15.避免从新处理数据
16.选择正确的数据格式
17.设置适当的背景图片
18.下降Web内容的影响
19.设置阴影路径
20.优化TableView
21.选择正确的数据存储方式
中级性能提高
如今,在进行代码优化时,你已经可以完成一些初级性能优化了。可是下面还有另一些优化方案,虽然可能不太明显(取决于程序的架构和相关代码),可是,若是可以正确的利用好这些方案,那么它们对性能的优化将很是明显!
9) 重用和延迟加载View
程序界面中包含更多的view,意味着界面在显示的时候,须要进行更多的绘制任务;也就意味着须要消耗更多的CPU和内存资源。特别是在一个UIScrollView里面加入了许多view。
这种状况的管理技巧能够参考UITableView和UICollectionView的行为:不要一次性建立全部的subview,而是在须要的时候在建立view,而且当view使用完毕时候将它们添加到重用队列中。
这样就能够仅在UIScrollView滚动的时候才配置view,以此能够避免分配建立view的带来的成本——这多是很是耗资源的。
如今有这样的一个问题:在程序中须要显示的view在什么时机建立(好比说,当用户点击某个按钮,须要显示某个view)。这里有两种可选方法:
在屏幕第一次加载以及隐藏的时候,建立view;而后在须要的时候,再把view显示出来。
直到须要显示view的时候,才建立并显示view。
每种方法都有各自的优势和缺点。第一种方法须要消耗更多的内容,由于建立出来的view一直占据着内存,直到view被release掉。不过,使用这种方法,当用户点击按钮时,程序会很快的显示出view,由于只须要修改一下view的可见性便可。而第二种方法则产生相反的效果;当须要的时候猜建立view,这会消耗更少的内存;不过,当用户点击按钮的时候,不会当即显示出view。
10) 缓存、缓存、缓存
在开发程序时,一个重要的规则就是“缓存重要的内容”——这些内容通常不会改变,而且访问的频率比较高。
能够缓存写什么内容呢?好比远程服务器的响应内容,图片,甚至是计算结果,好比UITableView的行高。
NSURLConnection根据HTTP头的处理过程,已经把一些资源缓存到磁盘和内存中了。你甚至能够手动建立一个NSURLRequest ,让其只加载缓存的值。
下面的代码片断通常用在为图片建立一个NSURLRequest:
注意:你可使用NSURLConnection抓取一个URL请求,可是一样可使用AFNetworking来抓取,这种方法不用修改全部网络相关的代码——这是一个技巧!
更多关于HTTP 缓存, NSURLCache, NSURLConnection 以及相关的内容, 那么看一下NSHipster中的the NSURLCache entry。
若是你须要缓存的内容没涉及到HTTP请求,那使用NSCache。NSCache的外观和行为与NSDictionary相似, 可是,当系统须要回收内存时,NSCache会自动的里面存储的内容。Mattt Thompson 在NSHipster上写了一篇关于NSCache很是不错的文章。
更多关于HTTP缓存的内容,建议读一下Google的这篇文章:best-practices document on HTTP caching。
11) 考虑绘制
这些方法的复杂程度不一样,性能也有区别。这篇关于iOS中图形性能的文章值得一读。其中Andy Matuschak(曾经是苹果的UIKit小组的组员)对这篇文章的评论中,对于不一样的方法及其性能权衡有很是好的一个看法。
简单来讲,使用预渲染图片技术是最快的,由于iOS中不用等到在屏幕上显示的时候才建立图形和对形状进行绘制(图片已经建立好了!)。这样带来的问题是须要把全部的图片都放到程序bundle中,从而增长了程序的大小。所以使用可伸缩图片在这里将排上用场了:能够移除“浪费”空间的图片——iOS能够重复利用。而且针对不一样的元素(例如按钮)不须要建立不一样的图片。
不过,使用图片的话会失去代码对图片的控制能力,进而针对不一样的程序,就须要重复的生成每个须要的图片,并反复的放到每一个程序中。这个处理过程通常会比较慢。另一点就是若是你须要一个动画,或者许多图片都要进行轻微的调整(好比多个颜色的覆盖),那么须要在程序中加入许多图片,进而增长了程序bundle的大小。
总的来讲,要考虑一下什么才是最重要的:绘制性能仍是程序大小。通常来讲都重要,因此在同一个工程中,应该两种都应考虑。
12) 处理内存警告
当系统内存偏低时,iOS会通知全部在运行的程序。苹果的官方文档中介绍了如何处理低内存警告:
If your app receives this warning, it must free up as much memory as possible. The best way to do this is to remove strong references to caches, image objects, and other data objects that can be recreated later.
若是程序收到了低内存警告,在程序中必须尽可能释放内存。最佳方法就是移除强引用的涉及到的缓存,图片对象,以及其它能够在以后使用时还能够从新建立的数据对象。
UIKit中提供了以下几种方法来接收低内存(low-memory)警告:
实现app delegate中的applicationDidReceiveMemoryWarning: 方法。
在UIViewController子类中重写(Override)didReceiveMemoryWarning方法。
在通知中内心面注册UIApplicationDidReceiveMemoryWarningNotificatio通知。
在收到以上任意的警告时,须要当即释听任何不须要的内存。
例如,UIViewController的默认状况是清除掉当前不可见的view;在UIViewController的子类中,能够清除一些额外的数据。程序中不没有显示在当前屏幕中的图片也能够release掉。
当收到低内存警告时,尽可能释放内存是很是重要的。不然,运行中的程序有可能会被系统杀掉。
不过,在清除内存时要注意一下:确保被清除的对象以后还能够被建立出来。另外,在开发程序的时候,请使用iOS模拟器中的模拟内存警告功能对程序进行测试!
13) 重用花销很大的对象
当使用这些对象时,为了不性能上的瓶颈,能够尝试尽可能重用这些对象——在类中添加一个属性或者建立一个静态变量。
注意,若是使用静态变量的话,对象会在程序运行的时候一直存在,就像单例同样。
下面的代码演示建立一个延迟加载的日期格式属性。第一次调用属性的时候,会建立一个新的日期格式。以后再调用的话,会返回已经建立好的实例对象:
另外,还须要记住的是在设置NSDateFormatter的日期格式时,一样跟建立新的一个NSDateFormatter实例对象时同样慢!所以,在程序中若是须要频繁的处理日期格式,那么对NSDateFormatter进行重用是很是好的。
14) 使用Sprite Sheets
下面是两个很是不错的sprite sheets教程:
如何在Cocos2D中使用纹理包(Texture Packer)和像素格式来建立并优化Sprite Sheets 。(第二个教程详细的介绍了像素格式——在游戏中能够衡量性能的影响)
若是还不熟悉sprite sheets,能够看看这里的介绍:SpriteSheets – 视频, Part 1和 Part 2 。这两个视频的做者是Andreas Löw, 他是纹理包(Texture Packer)的建立者, 纹理包是建立sprite sheets的重要工具。
除了使用sprite sheets外,这里还介绍了一些用于游戏开发中的技巧,例如,若是你有不少sprite(好比射击类游戏中),那么能够重用sprite,而不用每次都建立sprite。
15) 避免从新处理数据
许多程序都须要从远程服务器中获取数据,以知足程序的需求。这些数据通常是JSON或XML格式。在请求和接收数据时,使用相同的数据结构很是重要。
为何呢?在内存中把数据转换为适合程序的数据格式是须要付出额外代价的。
例如,若是你须要在table view中显示一些数据,那么请求和接收的数据格式最好是数组格式的,这样能够避免一些中间操做——将数据转换为适合程序使用的数据结构。
相似的,若是程序是根据键来访问具体的值,那么最好请求和接收一个键/值对字典。
在第一时间得到的数据就是所须要格式的,能够避免将数据转换为适合程序的数据格式带来的额外代价。
16) 选择正确的数据格式
将数据从程序传到网络服务器中有多种方法,其中使用的数据格式基本都是JSON和XML。你须要作的就是在程序中选择正确的数据格式。
JSON的解析速度很是快,而且要比XML小得多,也就意味着只须要传输更少数据。而且在iOS5以后,已经有内置的JSON反序列化API了,因此使用JSON是很容易的。
不过XML也有它本身的优点:若是使用SAX方法来解析XML,那么能够边读XML边解析,并不用等到所有的XML获取到了才开始解析,这与JSON是不一样的。当处理大量数据时,这种方法能够提高性能并减小内存的消耗。
17) 设置适当的背景图片
在iOS编码中,跟别的许多东西相似,这里也有两种方法来给view设置一个背景图片:
1.可使用UIColor的colorWithPatternImge方法来建立一个颜色,并将这个颜色设置为view的背景颜色。
2.能够给view添加一个UIImageView子视图。
若是你有一个全尺寸的背景图片,那么应该使用UIImageView,由于UIColor的colorWithPatternImge方法是用来建立小图片的——该图片会被重复使用。此时使用UIImageView会节省不少内存。
不过,若是你计划用小图片当作背景,那么应该使用UIColor的colorWithPatternImge方法。这种状况下绘制速度会很快,而且不会消耗大量的内存。
18) 下降Web内容的影响
UIWebView很是有用。用它能够很容易的显示web内容,甚至能够构建UIKit空间难以显示的内容。
不过,你能够能已经注意到程序中使用的UIWebView组建没有苹果的Safari程序快。这是由于JIT编译限制了WebKit的Nitro引擎的使用。
所以为了得到更加的性能,须要调整一下HTML的大小。首先就是尽可能的摆脱JavaScript,并避免使用大的矿建,例如jQuery。有时候使用原始的JavaScript要比别的框架快。
另外,尽可能的异步加载JavaScript文件——特别是不直接影响到页面行为时,例如分析脚本。
最后——让使用到的图片,跟实际须要的同样大小。如以前提到的,尽可能使用sprite sheets,以此节省内存和提高速度。
更多相关信息,能够看一下: WWDC 2012 session #601 – 在iOS中优化UIWebView和网站中的Web内容。
19) 设置阴影路径
若是须要在view活layer中添加一个阴影,该如何处理呢?大多数开发者首先将QuartzCore框架添加到工程中,而后添加以下代码:
上面这种方法有一个问题,Core Animation在渲染阴影效果以前,必须经过作一个离屏(offscreen)才能肯定view的形状,而这个离屏操做很是耗费资源。下面方法能够更容易地让系统进行阴影渲染:设置阴影路径!
经过设置阴影路径,iOS就不用老是再计算该如何绘制阴影了。只须要使用你预先计算好的路径便可。有一点很差的是,根据view的格式,本身可能很难计算出路径。另一个问题就是当view的frame改变时,必须每次都更新一下阴影路径。
若是你想了解更多相关信息,可参看Mark Pospesel的一篇文章:shadowPath。
20) 优化TableView
Table views须要快速的滚动——若是不能的话,用户会感受到停顿。为了让table view平滑的滚动,确保遵循了以下建议:
1.设置正确的reuseIdentifer以重用cell。
2.尽可能将view设置为不透明,包括cell自己。
3.避免渐变,图像缩放以及离屏绘制。
4.若是row的高度不相同,那么将其缓存下来。
5.若是cell显示的内容来此网络,那么确保这些内容是经过异步来获取的。
6.使用shadowPath来设置阴影。
7.减小subview的数量。
8.在cellForRowAtIndexPath:中尽可能作更少的操做。若是须要作一些处理,那么最好作过一次以后,就将结果缓存起来。
9.使用适当的数据结构来保存须要的信息。不一样的结构会带来不一样的操做代价。
10.使用rowHeight, sectionFooterHeight 和 sectionHeaderHeight 来设置一个恒定 高度,而不要从delegate中获取。
21) 选择正确的数据存储方式
当须要存储和读取大量的数据时,该如何选择存储方式呢?有以下选择:
1.使用NSUserDefaults进行存储
2.保存为XML,JSON或Plist格式的文件
3.利用NSCoding进行归档
4.存储到一个本地数据库,例如SQLite。
5.使用Core Data.
使用NSUserDefaults有什么问题呢? 虽然NSUserDefaults很好而且容易,不过只只针对于存储小量数据(好比你的级别,或者声音是开或关)。若是要存储大量的数据,最好选择别的存储方式。
大量数据保存为结构化的文件也可能会带来问题。通常,在解析这些结构数据以前,须要将内容所有加载到内存中,这是很消耗资源的。虽然可使用SAX来处理XML文件,可是这有点复杂。另外,加载到内存中的全部对象,不必定所有都须要用到。
那么使用NSCoding来保存大量数据怎么样呢?由于它一样是对文件进行读写,所以依然存在上面说的问题。
要保存大量的数据,最好使用SQLite或Core Data。经过SQLite或Core Data能够进行具体的查询——只须要获取并加载须要的数据对象——避免对数据进行不合理的搜索。在性能方面,SQLite和Core Data差不大。
SQLite和Core Data最大的区别实际上就是用法上。Core Data表明一个对象模型,而SQLite只是一个DBMS。通常,苹果建议使用Core Data,不过若是你有特殊的缘由不能使用Core Data的话,可使用低级别的SQLite。
在程序中,若是选择使用SQLite,这里有个方便的库FMDB :能够利用该库操做SQLite数据库,而不用深刻使用SQLite C API。
高级
当且仅当下面这些技巧可以解决问题的时候,才使用它们:
22.加速启动时间
23.使用Autorelease Pool
24.缓存图片 — 或者不缓存
25.尽可能避免Date格式化
高级性能提高
寻找一些高明的方法,让本身变为一个全代码忍者?下面这些高级的性能优化技巧能够在适当的时候让程序尽量的高效运行!
22) 加速启动时间
能快速的启动程序很是重要,特别是在用户第一次启动程序时。第一映像对程序来讲很是重要!
让程序尽可能快速启动的方法就是尽可能以异步方式执行任务,例如网络请求,数据访问或解析。
另外,避免使用臃肿的XIBs,由于XIB的加载是在主线程中进行的。可是记住storyboard没有这样的问题——因此若是能够的话就使用storyboard吧!
注意:在利用Xcode进行调试时,watchdog不会运行,所在设备中测试程序启动性能时,不要将设备链接到Xcode。
23) 使用Autorelease Pool
NSAutoreleasePool负责释放一个代码块中的自动释放对象。通常都是由UIKit来建立的。不过有些状况下须要手动建立NSAutoreleasePool。
例如,若是在代码中建立了大量的临时对象,你将注意到内存使用量在增长,直到这些对象被释放。问题是只有当UIKit耗尽了 autorelease pool,这些对象才会被释放,也就是说当再也不须要这些对象以后,这些对象还在内存中占据着资源。
不过这个问题彻底能够避免:在@autoreleasepool代码块中建立临时对象,以下代码:
当每次迭代完以后,都会释放全部的autorelease对象。
关于NSAutoreleasePool的更多内容能够阅读苹果的官方文档。
24) 缓存图片--或者不缓存
iOS中从程序bundle中加载UIImage通常有两种方法。
第一种比较常见:imageNamed。
第二种方法不多使用:imageWithContentsOfFile
为何有两种方法完成一样的事情呢?imageNamed的优势在于能够缓存已经加载的图片。苹果的文档中有以下说法:
This method looks in the system caches for an image object with the specified name and returns that object if it exists. If a matching image object is not already in the cache, this method loads the image data from the specified file, caches it, and then returns the resulting object.
这种方法会在系统缓存中根据指定的名字寻找图片,若是找到了就返回。若是没有在缓存中找到图片,该方法会从指定的文件中加载图片数据,并将其缓存起来,而后再把结果返回。
而imageWithContentsOfFile方法只是简单的加载图片,并不会将图片缓存起来。这两个方法的使用方法以下:
那么该如何选择呢?
若是加载一张很大的图片,而且只使用一次,那么就不须要缓存这个图片。这种状况imageWithContentsOfFile比较合适——系统不会浪费内存来缓存图片。
然而,若是在程序中常常须要重用的图片,那么最好是选择imageNamed方法。这种方法能够节省出每次都从磁盘加载图片的时间。
25) 尽可能避免Date格式化
若是有许多日期须要使用NSDateFormatter,那么须要当心对待了。如以前(重用花销很大的对象)所提到的,不管何时,都应该尽可能重用NSDateFormatters。
然而,若是你须要更快的速度,那么应该使用C来直接解析日期,而不是NSDateFormatter。Sam Soffes写了一篇文章,其中提供了一些解析ISO-8601格式日期字符的串代码。你只须要简单的调整一下其中的代码就能够知足本身特殊的需求了。
这听起来不错把——不过,你相信这还有更好的一个办法吗?
若是你本身能控制处理日期的格式,那么能够选择 Unix timestamps(http://en.wikipedia.org/wiki/Unix_time)。Unix timestamps是一个简单的整数,表明了重新纪元时间(epoch)开始到如今已通过了多少秒,一般这个新纪元参考时间是00:00:00 UTC on 1 January 1970。
你能够很容易的见这个时间戳转换为NSDate,以下所示:
上面这个方法比C函数还要快!
注意:许多网络APIs返回的时间戳都是毫秒,所以须要注意的是在将这个时间戳传递给dateFromUnixTimestamp以前须要除以1000。
何去何从?
强烈建议对程序性能优化感兴趣的读者看看下面列出来的WWDC视频。在看视频以前,你须要注册一个Apple ID(注册后就能够观看全部WWDC2012的视频):
#406: Adopting Automatic Reference Counting
#238: iOS App Performance: Graphics and Animations
#242: iOS App Performance: Memory
#235: iOS App Performance: Responsiveness
#409: Learning Instruments
#706: Networking Best Practices
#514: OpenGL ES Tools and Techniques
#506: Optimizing 2D Graphics and Animation Performance
#601: Optimizing Web Content in UIWebViews and Websites on iOS
#225: Up and Running: Making a Great Impression with Every Launch
下面这些视频来自WWDC 2011 ,也很是有用:
#308: Blocks and Grand Central Dispatch in Practice
#323: Introducing Automatic Reference Counting
#312: iOS Performance and Power Optimization with Instruments
#105: Polishing Your App: Tips and tricks to improve the responsiveness and performance
#121: Understanding UIKit Rendering
这里还有更多相关视频,大多数来自iOS 5技术讲座:
Optimizing App Performance with Instruments
Understanding iOS View Compositing
基于 “Your iOS App Performance Hitlist” 视频,Ole Begemann写了一篇文章。苹果还提供了一篇很是好的文章:性能优化。其中提供的技巧和提示对程序性能提高颇有帮助。