25条提高iOS App性能的建议和技巧.docx
- 文档编号:9349832
- 上传时间:2023-05-18
- 格式:DOCX
- 页数:22
- 大小:28.60KB
25条提高iOS App性能的建议和技巧.docx
《25条提高iOS App性能的建议和技巧.docx》由会员分享,可在线阅读,更多相关《25条提高iOS App性能的建议和技巧.docx(22页珍藏版)》请在冰点文库上搜索。
25条提高iOSApp性能的建议和技巧
当我们开发iOS应用时,好的性能对我们的App来说是很重要的。
你的用户也希望如此,但是如果你的app表现的反应迟钝或者很慢就会让你得到不好的评论。
然而,由于IOS设备的限制有时很难工作得很正确。
我们开发时有很多需要我们记住这些容易忘记的决定对性能的影响。
这是为什么我写这篇文章的原因。
这篇文章用备忘录的形式集合了25个技巧和诀窍可以用来提高你的app性能。
所以耐心的阅读来给你未来的App一个很不错的提高。
Note:
在优化代码之前,必须保证有个需要解决的问题!
不要陷入"pre-optimizing(预优化)"你的代码。
勤用Instruments分析你的代码,发现任何一个需要提高的地方。
MattGalloway写了一个使用Instruments优化代码的的教程
以下这些技巧分为三个不同那个的级别---基础,中级,高级。
基础
这些技巧你要总是想着实现在你开发的App中。
1. 用ARC去管理内存(UseARCtoManageMemory)
2.适当的地方使用reuseIdentifier(UseareuseIdentifierWhereAppropriate)
3.尽可能设置视图为不透明(SetViewasOpaqueWhenPossible)
4.避免臃肿的XIBs(AvoidFatXiBs)
5.不要阻塞主进程(Don'tBlocktheMainThread)
6.调整图像视图中的图像尺寸(SizeImagestoImageViews)
7.选择正确集合(ChoosetheCorrectCollection)
8.启用Gzip压缩(EnableGZIPCompression)
中级
这些技巧是当你遇到更复杂的情况的时候使用。
9.重用和延迟加载视图(ReuseandLazyLoadViews)
10.缓存,缓存,缓存(Cache,Cache,Cache)
11.考虑绘图(ConsiderDrawing)
12.处理内存警告(HandleMemoryWarnings)
13.重用大开销对象(ReuseExpensiveObjects)
14.使用精灵表(UseSpriteSheets)
15.避免重复处理数据(AvoidRe-ProcessingData)
16.选择正确的数据格式(ChoosetheRightDataFormat)
17.适当的设置背景图片(Set BackgroundImagesAppropriately)
18.减少你的网络占用(ReduceYourWebFootprint)
19.设置阴影路径(SettheShadowPath)
20.你的表格视图OptimizeYourTableViews)
21.选择正确的数据存储方式(ChooseCorrectDataStorageOption)
高级
这些技巧你应该只在你很积极认为它们能解决这个问题,而且你觉得用它们很舒适的时候使用。
22.加速启动时间(SpeedupLaunchTime)
23.使用自动释放池(UseAutoReleasePool)
24.缓存图像(CacheImages-Ornot )
25.尽可能避免日期格式化器(AvoidDateFormattersWherePossible)
没有其他的,一起去看看这些技巧吧!
基础的性能提升
1)用ARC去管理内存
ARC是伴随IOS5一起发布的,它用来消除常见的的内存泄漏。
ARC是"AutomaticReferenceCounting"的缩写。
它自动管理你代码中的retain/release循环,这样你就不必手动做这事儿了。
下面这段代码展示了创建一个view的常用代码
1 UIView*view=[[UIViewalloc]init];
2 //...
3 [self.viewaddSubview:
view];
4 [viewrelease];
这里极其容易忘记在代码结束的地方调用release,ARC将会自动的,底层的为你做这些工作。
除了帮助你你避免内存泄漏,ARC还能保证对象不再使用时立马被回收来提高你的性能。
你应该在你的工程里多用ARC。
这里是一些学习更多关于ARC的非常棒的资源
值得注意的是ARC不能消除所有的内存泄漏。
你依然有可能内存泄漏,这主要可能是由于blocks(块),引用循环,CoreFoundation对象管理不善(通常是C结构体,或者是确实很糟糕的代码)。
2)适当的地方使用reuseIdentifier
在app开发中的一个常见的为UITableViewCells,UICollectionViewCells,UITableViewHeaderFooterViews设置一个正确的reuseIdentifier(重用标识)。
为了最大化性能,一个tableView的数据源一般应该重用UITableViewCell对象,当它在tableView:
cellForRowAtIndexPath:
中分配数据给cells的时候。
一个表视图维护了一个UITableViewCell对象的队列或者列表,这些对象已被数据源标记为重用。
如果你不用reuseIdentifier会怎么样呢?
如果你用,你的tableview每显示一行将会配置一个全新的cell。
这是非常费事的操作而且绝对会影响你app滚动的性能。
自从引进了iOS6,你应该为headerandfooter视图设置reuseIdentifiers,就像在UICollectionView’scells和supplementaryviews(补充视图)一样。
使用reuseIdentifiers,当你的数据源要求提供一个新的cell给tableview的时候调用这个方
1 NSString*CellIdentifier=@"Cell";
2
3 UITableViewCell*cell=[tableViewdequeueReusableCellWithIdentifier:
CellIdentifierforIndexPath:
indexPath];
3)可能的时候设置视图为不透明
如果你有不透明视图(opaqueviews)--也就是说,没有透明度定义的视图,你应该设置他们的opaque属性为YES。
为什么?
这会允许系统以最优的方式绘制你的views。
这是一个简单的属性可以在InterfaceBuilder和代码中设置。
这个属性提供了一个提示给图系统如何对待这个视图。
如果设置为YES,绘制系统将会把这个视图视为完全不透明。
这样允许系统优化一些绘制操作和提高性能。
如果设置为NO,绘图系统会复合这个视图和其他的内容,这个属性的默认值是YES
在相对静态的屏幕上,设置opaque属性不会有什么大问题。
尽管如此,如果你的视图是嵌入在一个scrollView,或者是一个复杂的动画的一部分,不设置这个属性绝对会影响你的程序的性能。
你也可以使用Debug\ColorolorBlendedLayers选项在你的模拟器中形象化的看见没有设置为不透明(opaque)的视图.你的目标应该是尽可能多的设置视图为透明。
4) 避免臃肿的XIB文件
故事板,由iOS5引进,很快的替代XIBs。
尽管如此,XIBs在一下情况下依然是很有用的。
如果你需要在IOS5之前版本的设备上运行或者你想自定义重用的视图,那么你确实不能避免使用它们。
如果你专注使用XIBs,那么让它们尽量的简单。
尝试为一个试图控制器创建一个XIB,如果可能的话,把一个视图控制器的视图分层管理在单独的XIBs中。
注意当你加载一个XIB到内存的时候,它所有的内容都会载入内存,包括所有的图片。
如果你有视图但不是要立即使用,那你就浪费了珍贵的内存。
值得注意的是这不会发生在故事板中,因为故事版只会在需要的时候实例化一个视图控制器。
当你载入一个xib,所有的图像文件会被缓存,如果是开发OSX,那么音频文件也会被缓存。
如是说:
当你载入一个包含了图和声音资源引用的nib文件时,nib加载代码读取实际的图片文件和音频文件到内存中并缓存它。
在OSX中,图片和音频资源被存储在已命名的缓存中这样你可以在之后需要的时候访问它们。
在iOS中,只有图片资源被缓存,访问图片,你使用NSImage或者UIImage的imageNamed:
方法来访问,具体使用取决于你的平台。
显然这也发生在使用故事板的时候。
尽管如此,我还不能找到这种说法的证据。
如果你知道,请给我留言。
想学习更多关于故事板的更多内容吗?
看看MatthijsHollemans的
5)不要阻塞主进程
你永远不应该在主线程中做任何繁重的工作。
这是因为UIKIt的所有工作都在主线程中进行,比如绘画,管理触摸,和响应输出。
你的app的所有工作都在主线程上进行就会有阻塞主线程的风险,你的app会表现的反应迟钝。
这是在AppStore里获一星评论的快速途径!
(作者卖萌..)
阻塞主线程最多的情况就是发生在你的app进行I/O操作,包括牵扯到任何需要读写外部资源的任务,比如读取磁盘或者网络
你可以异步的执行网络任务使用NSURLConnection中的这个方法:
1 +(void)sendAsynchronousRequest:
(NSURLRequest*)requestqueue:
(NSOperationQueue*)queuecompletionHandler:
(void (^)(NSURLResponse*,NSData*,NSError*))handler
或者使用第三方框架比如 AFNetworking.
如果你在做任何大开销的操作(比如执行一个耗时的计算,或者读写磁盘)使用GrandCentralDispatch(GCD)或者NSOperations和NSOperationQueues.
使用GCD的模板如下代码所示:
01dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^{
02
03 //switchtoabackgroundthreadandperformyourexpensiveoperation
04
05
06
07 dispatch_async(dispatch_get_main_queue(),^{
08
09 //switchbacktothemainthreadtoupdateyourUI
10
11
12
13 });
14
15 });
这里为什么dispatch_async嵌套在第一个的里面?
这是因为任何UIKit相关的代码都必须在主线程上执行。
6)调整图像视图中的图像尺寸
如果你用UIImageView呈现app束中的图片时,确认图片和UIImageView的尺寸相同。
缩放图片会非常的耗时,特别是当你的UIImageView被嵌入UIScrollView。
如果图片是从远程服务器上下载的,有时你没法控制图片尺寸,或者你不能在服务器上在下载之前缩放它。
在这些情况下你可以在图片下载完成后手动缩放一次,最好是在后台进程中。
然在UIImageView中使用调整尺寸之后的图片。
7)选择正确集合
学着怎么在手头工作中使用最合适的类或对象是写出高效代码的基本。
当时用集合是(collections),这个说法特别对。
可喜的是在苹果开发者文档( CollectionsProgrammingTopics)中有详细解释可用类之间的关系,还有解释各个类的适用情况。
这个文档是每个使用集合的人的必读文档。
这是一个最常见的集合类型的快速简介:
∙Arrays:
有序的值的列表,用index快速查找,通过值查找慢,insert/delete操作慢。
∙Dictionaries:
存储键/值对.用index快速查找。
∙Sets:
无序的值列表。
通过值快速查找,insert/delete快。
8)启用Gzip压缩
大量和持续增长的app依赖从远端服务器或者外部APIs获取的外部数据。
某些时候你可能会开发一些需要下载XML,JSON,HTML或者其他文本格式的应用。
问题是移动设备不能保证网络环境,用户可能一分钟在边缘网络,下一分钟又是3G网络,无论什么情况下,你不想你的用户一直等待。
一个减少文件大小并加速下载的网络资源的方法是同时在你的服务器和客户端上使用GZIP压缩,对于文本数据这种有高比率压缩的数据来说非常有用。
好消息是iOS早已默认支持GZIP压缩,如果你是使用NSURLConnection或者建立在这之上的框架比如AFNetworking。
更好的消息是一切云服务提供商像 GoogleAppEngine早已发送压缩之后的响应数据。
这里有一篇文章greatarticleaboutGZIPcompression 介绍如何在你的Apache或IIS服务器上启用GZIP。
中级性能提升
好的,当谈到优化你的代码时,你应该很自信你已经初级的方法已经完全掌握了。
但有时候有的问题的解决方法并不是那么显而易见,它由你app的结构和代码决定,尽管如此,在正确的上下文中,它们可能是没有价值的。
9)重用和延迟加载视图
越多的视图就有越多的绘图操作,最终意味着更多的CPU和内存开销。
这说得特别对如果你的app嵌入很多视图在UIScrollView时。
管理这个的技巧是去模拟UITableView和UICollectionView的行为:
不要一次创建所有的子视图,而是在需要的时候创建,然后把他们假如重用队列中。
这样,你只需要在视图浮动时配置你的视图,避免昂贵的资源分配开销。
视图创建的时机问题也同样适用于你app的其他地方。
试想当你点击一个button时呈现一个视图的情景。
至少有两种方法:
1.屏幕第一次载入时创建视图并隐藏它。
当你需要的时候,显示出来。
2.需要呈现的时候一次创建视图并显示它。
每种方法都有各自的优缺点
使用第一种方法,你消耗了更多内存因为从创建开始到它释放前你都保持了它的内存,然而,当你点击button的时候,你的app会表现得响应快速因为它只需要更改视图的可视化属性。
使用第二种方法会有相反的效果,在需要的时候创建视图,消耗更少的内存,但当button被点击时应用会表现得不那么响应快速。
10)缓存,缓存,缓存
在开发应用时的一个伟大的经验是"Cachewhatmatters"--也就是说那些不大会改变但会平凡被访问的东西。
你能缓存些什么呢?
缓存的候选项有远程服务器的响应,图片,已计算过的值(比如UITableView的行高)。
NSURLConnection根据处理的Http头缓存资源到磁盘或者内存中,你甚至可以手动创建一个NSURLRequest值加载缓存过的值。
这里有一段很棒的代码,用在任何时候你需要针对一个不大会改变的图片创建一个NSURLRequest。
01 +(NSMutableURLRequest*)imageRequestWithURL:
(NSURL*)url{
02
03 NSMutableURLRequest*request=[NSMutableURLRequestrequestWithURL:
url];
04
05
06 request.cachePolicy=NSURLRequestReturnCacheDataElseLoad; //thiswillmakesuretherequestalwaysreturnsthecachedimage
07
08 request.HTTPShouldHandleCookies=NO;
09
10 request.HTTPShouldUsePipelining=YES;
11
12 [requestaddValue:
@"image/*" forHTTPHeaderField:
@"Accept"];
13
14 return request;
15
16 }
注意,你可以通过NSURLConnection获取取一个URL请求,AFNetworking也可以。
有了这个技巧这样你不用改变任何你的网络代码。
如果要缓存不牵扯到HTTP请求的其他东西,NSCache是很好的选择。
NSCache像NSDictionary,但是当系统需要回收内存的时候会自动的移除内容。
对HTTPCache感兴趣并想学更多的内容?
推荐阅读这篇文章best-practicesdocumentonHTTPcaching
11)考虑绘图
在IOS中有很多方法可以制作拥有很棒外观的buttons,你可以是由全尺寸的图像,也可以使用调整尺寸之后的图像,或者你用CALayer,CoreGraphics,甚至OpenGL手动的它们。
当然,每种途径都有不同的复杂度级别和不同的性能,这篇文章非常值得一读postaboutiOSgraphicsperformancehere,这是AppleUIKit团队成员AndyMatuschak发表的文章,里面对各种方法有一些非常棒的见解和对性能的权衡。
使用预渲染图片更快,因为iOS不用创建一张图像和绘制图形到屏幕上(图像已经处理好了)。
问题是你需要全部把这些图片放进应用束里,增加它的尺寸。
那就是为什么使用可调整尺寸的图片是那么好:
你通过移除”浪费了的“图片空间来节约空间。
你也不需要为不同的元素生成不同的图片。
(例如buttons)
尽管如此,用图片你会失去代码调整你图片的能力,需要一次又一次的生成它们然后把它们加入到应用中。
这是个缓慢的过程。
另外一点如果你有动画或者很多张稍微变化的图片(例如颜色叠加),你需要加很多的图片增加了应用束的大小。
总结一下,你需要想对你来说最重要的是什么:
绘图性能还是app的大笑.通常两个都很重要,所以你会在一个工程里使用这两种方法。
12)处理内存警告
当系统内存低的时候iOS会通知所有的正在运行的app,关于低内存警告的处理苹果官方文档 officialAppledocumentation描述:
如果你的应用收到这个警告,它必须尽可能多的释放内存。
最好的方法是移除对缓存,图像对象,和其他稍后要创建的对象的强引用。
幸运的是,UIKit提供了一些方法去接收低内存警告:
∙实现App代理中的applicationDidReceiveMemoryWarning:
方法。
∙重载你自定义UIViewController子类中的didReceiveMemoryWarning方法。
∙注册接收UIApplicationDidReceiveMemoryWarningNotification的通知
一旦收到这些警告,你的处理方法必须立刻响应并释放不必要的内存。
举例,如果视图当前不可见,UIViewController的默认行为是清除这些视图;子类可以通过清除额外的数据结构来补充父类的默认行为。
一个应用程序维护一个图片的缓存,没有在屏幕上的图片都会被释放。
一旦收到内存警告,释放可能的全部内存是很重要的,否则你就有让你的app被系统杀死的的风险。
尽管如此,开始扑杀对象释放内存的时候要小心,因为你需要保证它们会在之后重新创建。
当你开发app的时候,用你的模拟器上的模拟内存警告功能测试这种情况。
13)重用大开销对象
有的对象的初始化非常慢--NSDateFormatter和NSCalendar是两个例子,但是你不能避免使用它们,当你从JSON/XML响应中解析日期时。
避免使用这些对象时的性能瓶颈,试着尽可能的重用这些对象。
你可以加入你的类中成为一个属性,也可以创建为静态变量。
注意如果你选择了第二种方式,这个对象在app运行的时候会一直保持在内存里,像单例一样。
下面这段代码演示了NSDateFomatter作为一个属性的lazy加载,第一次被调用然后创建它,之后就使用已创建在的实例
01 //inyour.horinsideaclassextension
02
03 @property(nonatomic,strong)NSDateFormatter*formatter;
04
05
06 //insidetheimplementation(.m)
07
08 //Whenyouneed,justuseself.formatter
09
10 -(NSDateFormatter*)formatter{
11
12 if (!
_formatter){
13
14 _formatter=[[NSDateFormatteralloc]init];
15
16 _formatter.dateFormat=@"EEEMMMddHH:
mm:
ssZyyyy"; //twitterdateformat
17
18 }
19
20 return _formatter;
21
22 }
同样要记住设置一个NSDateFormatter的日期格式几乎跟创建一个新的一样慢。
因此,如果在你的应用中你频繁需要处理多个日期格式,你的代码应该获利于初始化创建,重用,多个NSDateFormatter对象。
14) 使用精灵表
你是一个游戏开发者吗?
精灵表是你的好朋友之一.精灵表让绘制比标准屏幕绘制方法更快速,消耗更少的内存。
这里有两个很棒的精灵表使用的教程
1.
第二个教程详细覆盖了像素格式,它可以对游戏性能有一个可衡量的影响。
如果对精灵表还不是很熟悉,一个很好的介绍 SpriteSheets–TheMovie,Part1andPart2.这些视频的作者是AndreasLöw,一个最流行的创建精灵表的工具TexturePacker的创建者。
除了使用精灵表之外,之前已经说到的内容也可以用在游戏上.举个例子,如果你的游戏有很多精灵,比如在标准的敌人或炮弹射击游戏,你可以重用精灵表额如是每次重新创建它们。
15)避免重复处理数据
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 25条提高iOS App性能的建议和技巧 25 提高 iOS App 性能 建议 技巧