iOS最全机能优化之25个建议

来源:互联网 浏览:- 2020-03-31 09:41:17

跳槽求职群:138269539

作者:HelloYeah

机能对 iOS 利用的开辟特别首要,如果你的利用落空反应或很慢,绝望的用户会在App Store写满差评。但是因为iOS装备的限定,偶然搞好机能是一件难事。开辟过程中你会有很多需求重视的事项,也很容易在做出挑选时健忘考虑机能影响。本文针对不合阶段开辟者提出了25个机能优化建议

初学者机能晋升这个部分努力于一些能进步机能的根基改变。但所有层次的开辟者都有可能会从这个记录了一些被忽视的项目标小小的机能备忘录里获得一些晋升。

1.用ARC办理内存

ARC(Automatic Reference Counting, 主动援引计数)和iOS5一路公布,它避免了最多见的也就是常常是因为我们健忘开释内存所酿成的内存泄漏。它主动为你办理retain和release的过程,所以你就没必要去手动干预了。下面是你会经常常利用往来来往建立一个View的代码段:

iOS最全性能优化之25个建议

忘失落代码段末端的release的确像记得用饭一样简朴。而ARC会主动在底层为你做这些事情。除帮你避免内存泄漏,ARC还可以帮你进步机能,它能包管开释失落不再需求的工具的内存。这都啥年代了,你应当在你的所有项目里利用ARC!


2.在精确的处所利用 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


3.尽可能把views设置为不透明

  • 如果你有透明的Views你应当设置它们的opaque(不透明)属性为YES。比方一个玄色半透明的可以设置为一个灰色不透明的View替代.启事是这会使体系用一个最优的体例衬着这些views。这个简朴的属性在IB或代码里都可以设定。
  • Apple的文档对为图片设置透明属性的描述是:(opaque)这个属性给衬着体系供应了一个若何措置这个view的提示。如果设为YES, 衬着体系就以为这个view是完整不透明的,这使得衬着体系优化一些衬着过程和进步机能。如果设置为NO,衬着体系一般地和别的内容构成这个View。默许值是YES。
  • 在相对比较运动的画面中,设置这个属性不会有太年夜影响。但是当这个view嵌在scroll view里边,或是一个复杂动画的一部分,不设置这个属性的话会在很年夜程度上影响app的机能。


4. 避免过于庞年夜的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:体例来获得图片资本。


5. 不要梗阻主线程

  • 永久不要使主线程承担过量。因为UIKit在主线程上做所有事情,衬着,办理触摸反应,回应输入等都需求在它下面完成。一向利用主线程的风险就是如果你的代码真的block了主线程,你的app会落空反应
  • 年夜部分停滞主过程的景象是你的app在做一些牵涉到读写外部资本的I/O操纵,比如存储或收集。或利用像 AFNetworking如许的框架来异步地做这些操纵。如果你需求做别的范例的需求破钞巨年夜资本的操纵(比如时候敏感的计较或存储读写)那就用 Grand Central Dispatch,或 NSOperation 和 NSOperationQueues.你可利用NSURLConnection异步地做收集操纵:
iOS最全性能优化之25个建议


6. 在Image Views中调剂图片年夜小

  • 如果要在UIImageView中显现一个来自bundle的图片,你应包管图片的年夜小和UIImageView的年夜小不异。在运行中缩放图片是很破钞资本的,特别是UIImageView嵌套在UIScrollView中的环境下。
  • 如果图片是从远端办事加载的你不克不及节制图片年夜小,比如鄙人载前调剂到适合年夜小的话,你可以鄙人载完成后,最好是用background thread,缩放一次,然后在UIImageView中利用缩放后的图片。


7. 挑选精确的Collection

学会挑选对业务场景最适合的类或工具是写出能效高的代码的根本。当措置collections时这句话特别精确。

Apple有一个 Collections Programming Topics 的文档详确介绍了可用的classes间的不同和你该在哪些场景中利用它们。这对任何利用collections的人来讲是一个必读的文档。呵呵,我就晓得你因为太长没看…这是一些常见collection的总结:

  • Arrays: 有序的一组值。利用index来lookup很快,利用value lookup很慢, 拔出/删除很慢。
  • Dictionaries: 存储键值对。 用键来查找比较快。
  • Sets: 无序的一组值。用值来查找很快,拔出/删除很快。


8. 翻开gzip紧缩

  • 年夜量app依靠于远端资本和第三方API,你可能会开辟一个需求从远端下载XML, JSON, HTML或别的格局的app。
  • 问题是我们的目标是挪动装备,是以你就不克不及希冀收集状况有多好。一个用户现在还在edge收集,下一分钟可能就切换到了3G。非论甚么场景,你必定不想让你的用户等太长时候。
  • 减小文档的一个别例就是在办事端和你的app中翻开gzip。这对笔墨这类能有更高紧缩率的数据来讲会有更明显的功效。好动静是,iOS已在NSURLConnection中默许支撑了gzip紧缩,当然AFNetworking这些基于它的框架亦然。像Google App Engine这些云办事供应者也已支撑了紧缩输入。


9. 重用和延迟加载(lazy load) Views

更多的view意味着更多的衬着,也就是更多的CPU和内存耗损,对那种嵌套了很多view在UIScrollView里边的app更是如此。这里我们用到的技能就是仿照UITableView和UICollectionView的操纵: 不要一次建立所有的subview,而是当需求时才建立,当它们完成了任务,把他们放进一个可重用的队列中。如许的话你就只需求在动弹产生时建立你的views,避免了不划算的内存分派。建立views的能效问题也合用于你app的别的方面。想象一下一个用户点击一个按钮的时候需求闪现一个view的场景。有两种实现体例:


  • 建立并埋没这个view当这个screen加载的时候,当需求时显现它;
  • 当需求时才建立并揭示。

每个计划都有其优错误谬误。用第一种计划的话因为你需求一开端就建立一个view并保持它直到不再利用,这就会更加耗损内存。但是这也会使你的app操纵更敏感因为当用户点击按钮的时候它只需求改变一下这个view的可见性。第二种计划则相反-耗损更少内存,但是会在点击按钮的时候比第一种稍显卡顿。


10. Cache, Cache, 还是Cache!

一个极好的准绳就是,缓存所需求的,也就是那些不年夜可能改变但是需求常常读取的东西。我们能缓存些甚么呢?

一些选项是,远端办事器的呼应,图片,乃至计较成果,比如UITableView的行高。NSURLConnection默许会缓存资本在内存或存储中按照它所加载的HTTP Headers。你乃至可以手动建立一个NSURLRequest然后使它只加载缓存的值。下面是一个可用的代码段,你可以可以用它去为一个根基不会改变的图片建立一个NSURLRequest并缓存它:

iOS最全性能优化之25个建议

重视你可以经由过程 NSURLConnection 获得一个URL request, AFNetworking也一样的。如许你就没必要为采取这条tip而改变所有的networking代码了。如果想体味更多关于HTTP caching, NSURLCache, NSURLConnection的相关知识,可以读下这篇文章()如果你需求缓存别的不是HTTP Request的东西,你可以用NSCache。NSCache和NSDictionary近似,不合的是体系收受领受内存的时候它会主动删失落它的内容。


11. 衡量衬着体例

在iOS中可以有很多体例做出标致的按钮。你可以用整幅的图片,可调年夜小的图片,uozhe可以用CALayer, CoreGraphics乃至OpenGL来画它们。当然每个不合的处理体例都有不合的复杂水安然平静呼应的机能。有一篇Apple UIKit team中的一员Andy Matuschak保举过的很棒的关于graphic机能的帖子很值得一读。


  • 简朴来讲,就是用事前衬着好的图片更快一些,因为如此一来iOS就免除了建立一个图片再画东西上去然后显现在屏幕上的法度。问题是你需求把所有你需求用到的图片放到app的bundle内里,如许就增加了体积 – 这就是利用可变年夜小的图片更好的处所了: 你可以省去一些不需求的空间,也不需求再为不合的元素(比如按钮)来做不合的图。但是,利用图片也意味着你落空了利用代码调剂图片的机动性,你需求一遍又一遍不竭地重做他们,如许就很浪费时候了,并且你如果要做一个动画结果,固然每幅图只是一些细节的转变你就需求很多的图片造成bundle年夜小的不竭增年夜。
  • 总得来讲,你需求衡量一下利害,究竟是要机能能还是要bundle保持适合的年夜小。


12. 措置内存警告

一旦体系内存太低,iOS会告诉所有运行中app。在官方文档中是如许记叙:如果你的app收到了内存警告,它就需求尽可能开释更多的内存。最好体例是移除对缓存,图片object和其他一些可以重修立的objects的strong references.荣幸的是,UIKit供应了几种汇集低内存警告的体例:

  • 在app delegate中利用applicationDidReceiveMemoryWarning: 的体例
  • 在你的自定义UIViewController的子类(subclass)中覆盖didReceiveMemoryWarning
  • 注册并领受 UIApplicationDidReceiveMemoryWarningNotification 的告诉


一旦收到这类告诉,你就需求开释任何不需求的内存利用。比方,UIViewController的默许行动是移除一些不成见的view, 它的一些子类则可以弥补这个别例,删失落一些分外的数据布局。一个有图片缓存的app可以移除不在屏幕上显现的图片。如许对内存警报的措置是很需求的,若不正视,你的app便可能被体系杀失落。但是,当你必然要确认你所挑选的object是可以被重现建立的来开释内存。必然要在开辟顶用摹拟器中的内存提示摹拟去测试一下。


13. 重用年夜开消工具

一些objects的初始化很慢,比如NSDateFormatter和NSCalendar。但是,你又不成避免地需求利用它们,比如从JSON或XML中剖析数据。想要避免利用这个工具的瓶颈你就需求重用他们,可以经由过程增加属性到你的class里或建立静态变量来实现。重视如果你要挑选第二种体例,工具会在你的app运行时一向存在于内存中,和单例(singleton)很类似。下面的代码说了然利用一个属性来延迟加载一个date formatter. 第一次调用时它会建立一个新的实例,今后的调用则将前往已建立的实例:

iOS最全性能优化之25个建议

还需求重视的是,其实设置一个NSDateFormatter的速率差不多是和建立新的一样慢的!所以如果你的app需求常常进行日期格局措置的话,你会从这个别例中获得不小的机能晋升。


14. 利用Sprite Sheets

你是一个游戏开辟者吗,那么Sprite sheets必然是一个你的最好的朋友了。Sprite sheet可让衬着速率加快,乃至比标准的屏幕衬着体例节流内存。我们有两个很好的关于Sprite的教程:


  • How To Use Animations and Sprite Sheets in Cocos2D
  • How to Create and Optimize Sprite Sheets in Cocos2D with Texture Packer and Pixel Formats


第二个教程涵盖了可能在很年夜程度上影响你游戏机能的pixel格局的细节。如果你对spirte sheet还不是很熟谙,可以看下这两个(youtube)视频SpriteSheets – The Movie, Part 1 和Part 2。视频的作者是建立Sprite sheet很风行的东西之一Texture Packer的作者Andreas L?w。除利用Sprite sheets,别的写在这里的建议当然也能够用于游戏开辟中。比如你需求很多的Sprite sheets,像仇敌,导弹之类的行动类必备元素,你可以重用这些sprites而不消每次都要从头建立。


15. 避免几次措置数据

很多利用需求从办事器加载服从所需的常为JSON或XML格局的数据。在办事器端和客户端利用不异的数据布局很首要。在内存中操纵数据使它们满足你的数据布局是开消很年夜的。

比如你需求数据来揭示一个table view,最好直接从办事器取array布局的数据以避免分外的中间数据布局改变。近似的,如果需求从特定key中取数据,那么就利用键值对的dictionary。


16. 挑选精确的数据格局

从app和收集办事间传输数据有很多计划,最多见的就是JSON和XML。你需求挑选对你的app来讲最适合的一个。

  • 剖析JSON会比XML更快一些,JSON也凡是更小更便于传输。从iOS5起有了官方内建的JSON deserialization 就更加便利利用了。
  • 但是XML也有XML的好处,比如利用SAX 来剖析XML就像剖析本地文件一样,你不需像剖析json一样比及全部文档下载完成才开端剖析。当你措置很年夜的数据的时候就会极年夜地减低内存耗损和增加机能。


17. 精确设定背景图片

在View里放背景图片就像很多别的iOS编程一样有很多体例:

  • 利用UIColor的 colorWithPatternImage来设置布风景;
  • 在view中增加一个UIImageView作为一个子View。


如果你利用全画幅的背景图,你就必须利用UIImageView因为UIColor的colorWithPatternImage是用来建立小的反复的图片作为背景的。这类景象下利用UIImageView可以节俭很多的内存:

iOS最全性能优化之25个建议

如果你用小图平铺来建立被页粳你就需求用UIColor的colorWithPatternImage来做了,它会更快地衬着也不会破钞很多内存:

iOS最全性能优化之25个建议


18. 减少利用Web特性

UIWebView很有效,用它来揭示网页内容或建立UIKit很难做到的动画结果是很简朴的一件事。


但是你可能有重视到UIWebView其实不像驱动Safari的那么快。这是因为以JIT compilation 为特性的Webkit的Nitro Engine的限定。


所以想要更高的机能你就要调剂下你的HTML了。第一件要做的事就是尽可能移除不需求的javascript,避免利用过年夜的框架。能只用原生js就更好了。别的,尽可能异步加载比方用户行动统计script这类不影响页面表达的javascript。


最后,永久要重视你利用的图片,包管图片的适合你利用的年夜小。利用Sprite sheet进步加载速率和节俭内存。更多相关信息可以看下 WWDC 2012 session #601 – Optimizing Web Content in UIWebViews and Websites on iOS


19. 设定Shadow Path

如安在一个View或一个layer上加一个shadow呢,QuartzCore框架是很多开辟者的挑选:

iOS最全性能优化之25个建议

看起来很简朴,对吧。但是,坏动静是利用这个别例也有它的问题… Core Animation不克不及不先在背景得出你的图形并加好暗影然后才衬着,这开消是很年夜的。利用shadowPath的话就避免了这个问题:

view.layer.shadowPath = [[UIBezierPath bezierPathWithRect:view.bounds] CGPath];


利用shadow path的话iOS就没必要每次都计较若何衬着,它利用一个事后计较好的途径。但问题是本身计较path的话可能在某些View中比较坚苦,且每当view的frame转变的时候你都需求去update shadow path.想体味更多可以看看Mark Pospesel的这篇。


20. 优化Table View

Table view需求有很好的动弹机能,不然用户会在动弹过程中发明动画的瑕疵。为了包管table view光滑动弹,确保你采纳了以下的办法:


  • 精确利用reuseIdentifier来重用cells
  • 尽可能使所有的view opaque,包含cell本身
  • 避免渐变,图片缩放,背景选人
  • 缓存行高
  • 如果cell内实际的内容来自web,利用异步加载,缓存请求成果
  • 利用shadowPath来画暗影
  • 减少subviews的数量
  • 尽可能不合用cellForRowAtIndexPath:,如果你需求用到它,只用一次然后缓存成果
  • 利用精确的数据布局来存储数据
  • 尽可能利用rowHeight, sectionFooterHeight 和 sectionHeaderHeight来设定牢固的高,不要请求delegate


21. 挑选精确的数据存储选项

  • 当作本地数据存储时你会怎样做?你有很多挑选,比如:
  • 利用NSUerDefaults
  • 利用XML, JSON, 或 plist
  • 利用NSCoding存档
  • 利用近似SQLite的本地SQL数据库
  • 利用 Core Data


NSUserDefaults的问题是甚么?固然它很nice也很便利,但是它只合用于小数据,比如一些简朴的布尔型的设置选项,再年夜点你就要考虑别的体例了。XML这类布局化档案呢?团体来讲,你需求读取全部文件到内存里去剖析,如许是很不经济的。利用SAX又是一个很费事的事情。NSCoding?不幸的是,它也需求读写文件,所以也有以上问题。


当存储年夜块数据时,以上的体例都不合用. 在这类利用处景下,利用SQLite 或 Core Data比较好。利用这些技术你用特定的查询语句就可以只加载你需求的工具。在机能层面来讲,SQLite和Core Data是很类似的。他们的不合在于详细利用体例。Core Data代表一个工具的graph model,但SQLite就是一个DBMS。Apple在一般环境下建议利用Core Data,但是如果你有来由不利用它,那么就去利用更加底层的SQLite吧。


22. 加快启动时候

疾速翻开app是很首要的,特别是用户第一次翻开它时,对app来讲,第一印象太太太首要了。


你能做的就是使它尽可能做更多的异步任务,比如加载远端或数据库数据,剖析数据。还是那句话,避免过于庞年夜的XIB,因为他们是在主线程上加载的。所以尽可能利用没有这个问题的Storyboards吧!重视,用Xcode debug时watchdog其实不运行,必然要把装备从Xcode断开来测试启动速率。


23. 利用Autorelease Pool

NSAutoreleasePool卖力开释block中的autoreleased objects。一般环境下它会主动被UIKit调用。但是有些状况下你也需求手动去建立它。

假定你建立很多临时工具,你会发明内存一向在减少直到这些工具被release的时候。这是因为只需当UIKit用光了autorelease pool的时候memory才会被开释。

好动静是你可以在你本身的@autoreleasepool里建立临时的工具来避免这个行动:

iOS最全性能优化之25个建议

这段代码在每次遍历后开释所有autorelease工具更多关于NSAutoreleasePool请参考官方文档。


24. 挑选是不是缓存图片

常见的从bundle中加载图片的体例有两种,一个是用imageNamed,二是用imageWithContentsOfFile,第一种比较常见一点。既然有两种近似的体例来实现不异的目标,那么他们之间的不同是甚么呢?


imageNamed的长处是当加载时会缓存图片。imageNamed的文档中这么说:这个别例用一个指定的名字在体系缓存中查找并前往一个图片工具如果它存在的话。如果缓存中没有找到呼应的图片,这个别例从指定的文档中加载然后缓存并前往这个工具。相反的,imageWithContentsOfFile仅加载图片。下面的代码说了然这两种体例的用法:

iOS最全性能优化之25个建议

那么我们应当若何挑选呢?如果你要加载一个年夜图片并且是一次性利用,那么就没需求缓存这个图片,用imageWithContentsOfFile足矣,如许不会浪费内存来缓存它。但是,在图片几次重用的环境下imageNamed是一个好很多的挑选。


25. 避免日期格局转换

如果你要用NSDateFormatter来措置很多日期格局,应当小心以待。就像先前提到的,任甚么时候候重用NSDateFormatters都是一个好的实际。但是,如果你需求更多速率,那么直接用C是一个好的计划。但是你信赖吗,我们另有更好的计划!如果你可以节制你所措置的日期格局,尽可能挑选Unix时候戳。你可以便利地从时候戳转换到NSDate:

iOS最全性能优化之25个建议

如许会比用C来剖析日期字符串还快!需求重视的是,很多web API会以微秒的情势前往时候戳,因为这类格局在javascript中更便利利用。记着用dateFromUnixTimestamp之前除以1000就好了。

保举浏览:河南热线

<fieldset id='wy'><fieldset></fieldset></fieldset><legend id='aSmGLYK'><big></big></legend>
    <tt id='srQdQRBX'><q></q></tt><cite id='lRtpbC'><basefont></basefont></cite>
        <bgsound id='ZGpAKY'><l></l></bgsound><strike></strike>
        <samp id='yJaCmikk'><acronym></acronym></samp><bdo id='ZhP'><thead></thead></bdo>