如何对定位和分析项目中影响性能的地方?以及如何进行性能优化?

定位方法:

instruments

在iOS上进⾏性能分析的时候,⾸先考虑借助instruments这个利器分析出问题出在哪,不要凭空想象,不然你可能把精⼒花在了1%的问题上,最后发现其实啥都没优化,⽐如要查看程序哪些部分最耗时,可以使⽤Time Profiler,要查看内存是否泄漏了,可以使⽤Leaks等。关于instruments⽹上有很多资料,作为⼀个合格iOS开发者,熟悉这个⼯具还是很有必要的。

优化建议:

⽤ARC管理内存

  • ARC(Automatic Reference Counting, ⾃动引用计数)和iOS5⼀起发布,它避免了最常见的也就是经常是由于我们忘记释放内存所造成的内存泄露。它⾃动为你管理retain和release的过程,所以你就不必去⼿动干预了。

下⾯是你会经常⽤来去创建⼀个View的代码段:

UIView *view = [[UIView alloc] init];
 ...
[self.view addSubview:view];
[view release];
  • 忘掉代码段结尾的release简直像记得吃饭⼀样简单。⽽ARC会⾃动在底层为你做这些⼯作。除了帮你避免内存泄露,ARC还可以帮你提⾼性能,它能保证释放掉不再需要的对象的内存。这都啥年代了,你应该在你的所有项⽬⾥使⽤ARC!

在正确的地⽅使⽤ reuseIdentifier

  • ⼀个开发中常⻅的错误就是没有给UITableViewCells, UICollectionViewCells,甚⾄是UITableViewHeaderFooterViews设置正确的reuseIdentifier。

  • 为了性能最优化,table view⽤ tableView:cellForRowAtIndexPath: 为rows分配cells的时候,它的数据应该重⽤⾃UITableViewCell。 ⼀个table view维持⼀个队列的数据可重⽤的UITableViewCell对象。不使⽤reuseIdentifier的话,每显示⼀⾏table view就不得不设置全新的cell。这对性能的影响可是相当⼤的,尤其会使app的滚动体验⼤打折扣。

  • ⾃iOS6起,除了UICollectionView的cells和补充views,你也应该在header和footer views中使⽤reuseIdentifiers

尽量把views设置为完全不透明

  • 如果你有透明的Views你应该设置它们的opaque(不透明)属性为YES。例如⼀个⿊⾊半透明的可以设置为⼀个灰⾊不透明的View替代.原因是这会使系统⽤⼀个最优的⽅式渲染这些views。这个简单的属性在IB或者代码⾥都可以设定。

  • Apple的⽂档对于为图⽚设置透明属性的描述是:(opaque)这个属性给渲染系统提供了⼀个如何处理这个view的提示。如果设为YES, 渲染系统就认为这个view是完全不透明的,这使得渲染系统优化⼀些渲染过程和提⾼性能。如果设置为NO,渲染系统正常地和其它内容组成这个View。默认值是YES。

  • 在相对⽐较静⽌的画⾯中,设置这个属性不会有太⼤影响。然⽽当这个view嵌在scroll view⾥边,或者是⼀个复杂动画的⼀部分,不设置这个属性的话会在很⼤程度上影响app的性能。

  • 换种说法,⼤家可能更好理解:只要⼀个视图的不透明度⼩于1,就会导致blending.blending操作在iOS的图形处理器(GPU)中完成的,blending主要指的是混合像素颜⾊的计算。举个例⼦,我们把两个图层叠加在⼀起,如果第⼀个图层的有透明效果,则最终像素的颜⾊计算需要将第⼆个图层也考虑进来。这⼀过程即为Blending。为什么Blending会导致性能的损失?原因是很直观的,如果⼀个图层是完全不透明的,则系统直接显示该图层的颜⾊即可。⽽如果图层是带透明效果的,则会引⼊更多的计算,因为需要把下⾯的图层也包括进来,进⾏混合后颜⾊的计算。

避免过于庞⼤的XIB

  • iOS5中加⼊的Storyboards(分镜)正在快速取代XIB。然⽽XIB在⼀些场景中仍然很有⽤。⽐如你的app需要适应iOS5之前的设备,或者你有⼀个⾃定义的可重⽤的view,你就不可避免地要⽤到他们。

  • 如果你不得不XIB的话,使他们尽量简单。尝试为每个Controller配置⼀个单独的XIB,尽可能把⼀个View Controller的view层次结构分散到单独的XIB中去。

  • 需要注意的是,当你加载⼀个XIB的时候所有内容都被放在了内存⾥,包括任何图⽚。如果有⼀个不会即刻⽤到的view,你这就是在浪费宝贵的内存资源了。Storyboards就是另⼀码事⼉了,storyboard仅在需要时实例化⼀个view controller.

  • 当你加载⼀个引⽤了图⽚或者声⾳资源的nib时,nib加载代码会把图⽚和声⾳⽂件写进内存。在OS X中,图⽚和声⾳资源被缓存在named cache中以便将来⽤到时获取。在iOS中,仅图⽚资源会被存进named caches。取决于你所在的平台,使⽤NSImage 或UIImage 的imageNamed:⽅法来获取图⽚资源。

不要阻塞主线程

  • 永远不要使主线程承担过多。因为UIKit在主线程上做所有⼯作,渲染,管理触摸反应,回应输⼊等都需要在它上⾯完成。⼀直使⽤主线程的⻛险就是如果你的代码真的block了主线程,你的app会失去反应

  • ⼤部分阻碍主进程的情形是你的app在做⼀些牵涉到读写外部资源的I/O操作,⽐如存储或者⽹络。或者使⽤像 AFNetworking这样的框架来异步地做这些操作。如果你需要做其它类型的需要耗费巨⼤资源的操作(⽐如时间敏感的计算或者存储读写)那就⽤ Grand Central Dispatch,或者 NSOperation 和NSOperationQueues.你可以使⽤NSURLConnection异步地做⽹络操作: +(void)sendAsynchronousRequest:(NSURLRequest )request queue:(NSOperationQueue )queuecompletionHandler:(void (^)(NSURLResponse, NSData, NSError*))handler

在Image Views中调整图⽚⼤⼩

  • 如果要在UIImageView中显示⼀个来⾃bundle的图⽚,你应保证图⽚的⼤⼩和UIImageView的⼤⼩相同。在运⾏中缩放图⽚是很耗费资源的,特别是UIImageView嵌套在UIScrollView中的情况下。

  • 如果图⽚是从远端服务加载的你不能控制图⽚⼤⼩,⽐如在下载前调整到合适⼤⼩的话,你可以在下载完成后,最好是⽤background thread,缩放⼀次,然后在UIImageView中使⽤缩放后的图⽚。

选择正确的Collection
学会选择对业务场景最合适的类或者对象是写出能效⾼的代码的基础。当处理collections时这句话尤其正确。

Apple有⼀个 Collections Programming Topics 的⽂档详尽介绍了可⽤的classes间的差别和你该在哪些场景中使⽤它们。这对于任何使⽤collections的⼈来说是⼀个必读的⽂档。

呵呵,我就知道你因为太⻓没看…这是⼀些常⻅collection的总结:

  • Arrays: 有序的⼀组值。使⽤index来lookup很快,使⽤value lookup很慢, 插⼊/删除很慢。

  • Dictionaries: 存储键值对。 ⽤键来查找⽐较快。

  • Sets: ⽆序的⼀组值。⽤值来查找很快,插⼊/删除很快

打开gzip压缩

  • ⼤量app依赖于远端资源和第三⽅API,你可能会开发⼀个需要从远端下载XML, JSON, HTML或者其它格式的app。

  • 问题是我们的⽬标是移动设备,因此你就不能指望⽹络状况有多好。⼀个⽤户现在还在edge⽹络,下⼀分钟可能就切换到了3G。不论什么场景,你肯定不想让你的⽤户等太⻓时间。

  • 减⼩⽂档的⼀个⽅式就是在服务端和你的app中打开gzip。这对于⽂字这种能有更⾼压缩率的数据来说会有更显著的效⽤。好消息是,iOS已经在NSURLConnection中默认⽀持了gzip压缩,当然AFNetworking这些基于它的框架亦然。像Google App Engine这些云服务提供者也已经⽀持了压缩输出。

推荐阅读更多精彩内容