iOS性能優(yōu)化系列篇之“優(yōu)化總體原則”

筆者由于在iOS開(kāi)發(fā)過(guò)程中做過(guò)一些優(yōu)化的工作,對(duì)iOS性能優(yōu)化有一些粗淺的認(rèn)識(shí),一直想把自己這些經(jīng)驗(yàn),簡(jiǎn)單總結(jié)一下。于是最近在工作閑暇時(shí)間,準(zhǔn)備針對(duì)iOS開(kāi)發(fā)的性能優(yōu)化寫一系列文章。

作為整個(gè)系列的第一篇,我打算針對(duì)iOS的優(yōu)化中的一些總體原則做一些總結(jié)。因?yàn)槲矣X(jué)得無(wú)論列表流暢度優(yōu)化也好、啟動(dòng)時(shí)間優(yōu)化也好還是說(shuō)其他方面的優(yōu)化,都有一些共性的原則,只有掌握了這些總體性的原則,才能夠更好的做優(yōu)化,給我們具體的優(yōu)化任務(wù)指明方向,讓我們少繞彎路。后面如果時(shí)間允許,我可能會(huì)寫一些關(guān)于列表流暢度、啟動(dòng)時(shí)間和內(nèi)存優(yōu)化等方面的文章。

我對(duì)優(yōu)化總體原則總結(jié)出包括不要提前過(guò)度優(yōu)化、要找到性能瓶頸、要在不同性能指標(biāo)間權(quán)衡、要理解優(yōu)化任務(wù)的底層運(yùn)行機(jī)制和要有技術(shù)保障體系五大原則,其中具體闡述每一個(gè)原則的時(shí)候并不局限于性能優(yōu)化方面,會(huì)發(fā)散到其他的相關(guān)領(lǐng)域,會(huì)對(duì)一些延伸的領(lǐng)域做一些簡(jiǎn)單的探討,希望能夠?qū)ψx者有一些啟示。以下是主要內(nèi)容。

一、不要提前過(guò)度優(yōu)化

這個(gè)原則包括優(yōu)化的過(guò)程中需要避免的兩個(gè)陷阱,即提前優(yōu)化和過(guò)度優(yōu)化。

提前優(yōu)化指的是在開(kāi)發(fā)的起始階段就把性能優(yōu)化作為一個(gè)重要的任務(wù)來(lái)考慮,在沒(méi)有實(shí)際數(shù)據(jù)指標(biāo)的基礎(chǔ)上,為了性能提前做的些盲目?jī)?yōu)化工作。

當(dāng)然這個(gè)觀點(diǎn)可能會(huì)引起爭(zhēng)議,因?yàn)樵谀承╅_(kāi)發(fā)領(lǐng)域,一些性能指標(biāo)以歷史的經(jīng)驗(yàn)來(lái)說(shuō),的確有很大概率甚至必然會(huì)有性能瓶頸的問(wèn)題,因此在架構(gòu)初期就需要考慮性能的問(wèn)題。 因此如果把“不要提前優(yōu)化“這個(gè)觀點(diǎn)推廣所有開(kāi)發(fā)領(lǐng)域上的話,我認(rèn)為可能不一定合適。但是如果把此觀點(diǎn)約束在iOS開(kāi)發(fā)這一領(lǐng)域內(nèi),我個(gè)人認(rèn)為還是成立的。因?yàn)樵谀壳半A段iOS平臺(tái)設(shè)備性能普遍較好,蘋果無(wú)論是硬件層面還是系統(tǒng)層面對(duì)性能方面都做了大量的優(yōu)化。所以我認(rèn)為性能方面并不是iOS開(kāi)發(fā)過(guò)程中需要首要考慮的因素。相比性能, 我個(gè)人認(rèn)為在iOS開(kāi)發(fā)的初始階段,以下幾個(gè)方面是更重要的,是需要首先考慮的。

首先需要考慮的是架構(gòu)的選擇,這里的架構(gòu)指的是Native架構(gòu)、web架構(gòu)、Native和web混合架構(gòu)和跨平臺(tái)的架構(gòu)。這里面我個(gè)人的意見(jiàn)是首先應(yīng)該盡量避免使用web架構(gòu),從Facebook早期的失敗經(jīng)驗(yàn)可以看出,web和Native相比的確存在諸多性能、體驗(yàn)等方面的問(wèn)題。連大廠都無(wú)法徹底改善webview的問(wèn)題,何況我們。但是在一些和用戶體驗(yàn)相比,對(duì)動(dòng)態(tài)化需求更加迫切的應(yīng)用場(chǎng)景下,是可以選擇web架構(gòu)的,比如大家都一直在吐槽某鐵路售票軟件。Native架構(gòu)的優(yōu)勢(shì)是產(chǎn)品體驗(yàn)好,對(duì)大多數(shù)iOS開(kāi)發(fā)者技術(shù)棧友好,缺點(diǎn)是由于蘋果對(duì)熱更新做了嚴(yán)格限制,導(dǎo)致一些動(dòng)態(tài)化的方案無(wú)法使用。Native和web混合架構(gòu)主要是在Native架構(gòu)上,在一些運(yùn)營(yíng)需求十分強(qiáng)烈的場(chǎng)景下(如電商等場(chǎng)景),某些模塊使用web開(kāi)發(fā),這樣既可以在App大部分場(chǎng)景下使用Native架構(gòu),保證用戶體驗(yàn),又滿足了部分場(chǎng)景動(dòng)態(tài)化的需求。跨平臺(tái)的架構(gòu)主要是可以減少多端開(kāi)發(fā)的成本,使用一套代碼完成iOS和Android兩個(gè)平臺(tái)的開(kāi)發(fā),目前主流的框架有ReactNative、Weex和Xamarin等。這些跨平臺(tái)架構(gòu)的愿景都很美好,但實(shí)際使用過(guò)程中,個(gè)人覺(jué)得現(xiàn)階段并不比使用Native架構(gòu)節(jié)省人力,其中會(huì)遇到許多已知的未知的坑,當(dāng)然作為新的技術(shù)我們應(yīng)該持開(kāi)發(fā)的心態(tài),但在使用時(shí)候也需要全面的評(píng)估,尤其作為一個(gè)可能有很長(zhǎng)生命周期的應(yīng)用,在使用非官方推薦的開(kāi)發(fā)架構(gòu)也好、開(kāi)源庫(kù)也好,如果后期無(wú)人維護(hù)的話,自己團(tuán)隊(duì)是不是有實(shí)力去接盤,如果不能,使用蘋果官方推薦的技術(shù)棧則更穩(wěn)妥些。

其次需要考慮的是開(kāi)發(fā)語(yǔ)言的選擇,這個(gè)方面其實(shí)在選擇了架構(gòu)之后,也將可選的開(kāi)發(fā)語(yǔ)言范圍縮小到幾個(gè)。而且實(shí)際項(xiàng)目開(kāi)發(fā)中并不難選,因?yàn)閳F(tuán)隊(duì)開(kāi)發(fā)人員的技術(shù)棧幾乎決定了使用的開(kāi)發(fā)語(yǔ)言,如果使用了大部分團(tuán)隊(duì)成員都不熟悉的語(yǔ)言,我相信即使所選語(yǔ)言在很多方面都有壓倒性的優(yōu)勢(shì),項(xiàng)目的推進(jìn)也不會(huì)十分順利。但是排除團(tuán)隊(duì)技術(shù)棧的因素,不同的開(kāi)發(fā)語(yǔ)言的確是各有千秋。大家都知道iOS開(kāi)發(fā)過(guò)程中,如果使用Native架構(gòu),官方的開(kāi)發(fā)語(yǔ)言是objc和swift。objc是早期iOS開(kāi)發(fā)的官方推薦語(yǔ)言,優(yōu)點(diǎn)是其動(dòng)態(tài)性,十分靈活,可以實(shí)現(xiàn)許多“黑魔法”,缺點(diǎn)語(yǔ)法略怪異(當(dāng)然對(duì)于iOS開(kāi)發(fā)者,使用久了也不覺(jué)得怪了),另外是對(duì)一些高級(jí)的語(yǔ)言特性支持的不是很好(記得最初使用objc開(kāi)發(fā)iOS應(yīng)用的時(shí)候,因?yàn)橐恍┨厥獾男枨蟆S捎趏bjc不支持namespace,給團(tuán)隊(duì)造成了很大的困擾)。swift是蘋果近年來(lái)主推的開(kāi)發(fā)語(yǔ)言, 其吸收了許多其他語(yǔ)言的先進(jìn)特性,也比較容易上手。關(guān)于兩種開(kāi)發(fā)語(yǔ)言的具體技術(shù)細(xì)節(jié),大家有興趣可以自己查看一些資料了解下。雖然蘋果一直在力推swift,但是目前在國(guó)內(nèi)iOS開(kāi)發(fā)領(lǐng)域,由于一些用戶基數(shù)大的主流App,均是在swift出現(xiàn)前使用objc編寫的,而且大多經(jīng)過(guò)了數(shù)年的版本迭代,加之早起swift ABI的不穩(wěn)定和版本之間升級(jí)需要較多工作,還有swift和objc混編的一些問(wèn)題,導(dǎo)致目前國(guó)內(nèi)主流App大多仍使用objc作為開(kāi)發(fā)語(yǔ)言。在一些創(chuàng)業(yè)公司,或者新的項(xiàng)目中,才有部分開(kāi)發(fā)者使用swift,當(dāng)然如果目光放長(zhǎng)遠(yuǎn)的話,未來(lái)一定是swift的天下,這兩年objc在每年的語(yǔ)言排名中逐年下降也側(cè)面印證了這一點(diǎn)。 除了官方推薦的objc和是swift之外,如果使用跨平臺(tái)等其他架構(gòu),還可以使用如js、c#等語(yǔ)言,有興趣的可以自行了解下。

再次需要考慮的是開(kāi)發(fā)過(guò)程中具體的代碼架構(gòu)的選擇,這里只簡(jiǎn)單談?wù)凬ative架構(gòu)下的代碼架構(gòu)選擇。 目前iOS開(kāi)發(fā)中常用的架構(gòu)有MVC 、MVVM、VIPER、MVP等。關(guān)于這些架構(gòu),網(wǎng)上目前有很多的介紹,大家如果對(duì)具體細(xì)節(jié)有興趣可以自行查閱。這里我只想補(bǔ)充一點(diǎn),大家在學(xué)習(xí)和實(shí)踐時(shí),不要盲目跟風(fēng)新技術(shù),比如MVVM等架構(gòu)未必比MVC好很多,MVC也未必是一個(gè)過(guò)時(shí)的框架。要知道很多新架構(gòu)帶來(lái)的擴(kuò)展性和解耦行都是通過(guò)引入間接層來(lái)實(shí)現(xiàn)的,隨之而來(lái)的可能是更多的膠水代碼和更復(fù)雜的代碼結(jié)構(gòu)。希望大家在選擇的時(shí)候能夠根據(jù)項(xiàng)目的特點(diǎn)和團(tuán)隊(duì)自身的狀況,選擇最適合自己團(tuán)隊(duì)和項(xiàng)目的代碼架構(gòu)。

除了上面說(shuō)的三點(diǎn),還有一些其他的關(guān)鍵點(diǎn)需要大家在項(xiàng)目初期考慮,比如如何在團(tuán)隊(duì)內(nèi)部達(dá)成統(tǒng)一的代碼風(fēng)格?一些關(guān)鍵的技術(shù)如何選型?如何保證代碼結(jié)構(gòu)清晰、簡(jiǎn)單、擴(kuò)展性好等等。性能問(wèn)題可以在項(xiàng)目后期開(kāi)始考慮,如果真的發(fā)現(xiàn)明顯的性能問(wèn)題再優(yōu)化也來(lái)得及。比如項(xiàng)目一開(kāi)始憑直覺(jué)感覺(jué)某一個(gè)模塊可能會(huì)有性能問(wèn)題,就盲目使用多線程,而不是根據(jù)實(shí)際情況具體問(wèn)題具體分析。會(huì)導(dǎo)致程序復(fù)雜且容易出現(xiàn)線程安全問(wèn)題。

過(guò)度優(yōu)化是指為了優(yōu)化性能,過(guò)度增加系統(tǒng)復(fù)雜度和維護(hù)成本,使得開(kāi)發(fā)周期變長(zhǎng)。雖然可能性能上帶來(lái)了一定的提升,但是和過(guò)度優(yōu)化而導(dǎo)致的這些缺點(diǎn)來(lái)比,這么做顯而易見(jiàn)是得不償失的。

筆者在工作過(guò)程中,發(fā)現(xiàn)許多同學(xué)在性能優(yōu)化過(guò)程中,都容易陷入這種過(guò)度優(yōu)化的陷阱。比如這一個(gè)簡(jiǎn)單的設(shè)置界面,一共只有十幾個(gè)靜態(tài)的cell, 如果去考慮圓角性能、離屏渲染、圖片緩存、高度緩存、異步渲染甚至緩存布局信息,這些無(wú)疑是陷入了過(guò)度優(yōu)化的陷阱,在這個(gè)應(yīng)用背景下,簡(jiǎn)單快速的實(shí)現(xiàn)功能才是第一要?jiǎng)?wù)。在目前蘋果的開(kāi)發(fā)框架和平臺(tái)上,一般如果出現(xiàn)性能問(wèn)題,以我的實(shí)際經(jīng)驗(yàn)來(lái)說(shuō),問(wèn)題大部分是出在業(yè)務(wù)邏輯上面,所以遇到問(wèn)題首先需要在業(yè)務(wù)邏輯上找問(wèn)題,一些過(guò)度的極限的優(yōu)化,完全是沒(méi)有必要的。

其實(shí)不光是性能優(yōu)化,我發(fā)現(xiàn)許多同學(xué)在日常開(kāi)發(fā)中,處處都有過(guò)度設(shè)計(jì)的情況。比如設(shè)計(jì)模式中的design happy這一陷阱,許多初學(xué)者在剛開(kāi)始學(xué)習(xí)設(shè)計(jì)模式的時(shí)候,十分癡迷設(shè)計(jì)模式在解決不同問(wèn)題時(shí),對(duì)代碼的解耦性和可擴(kuò)展性上的威力,在開(kāi)發(fā)過(guò)程中會(huì)時(shí)時(shí)刻刻想著應(yīng)該用什么設(shè)計(jì)模式。結(jié)果導(dǎo)致很多的過(guò)度設(shè)計(jì),其實(shí)我們寫代碼過(guò)程中,如果能遵守基本的SOLID原則,大部分情況下就可以寫出高質(zhì)量的代碼。

另外一個(gè)例子是組件化。近期iOS組件化是一個(gè)十分流行的話題,有許多團(tuán)隊(duì)提出了不同的組件化方案。實(shí)際項(xiàng)目中,團(tuán)隊(duì)在是否采用組件化方式開(kāi)發(fā)的選擇上,我希望要結(jié)合項(xiàng)目特點(diǎn)和團(tuán)隊(duì)組織架構(gòu)形式具體問(wèn)題具體分析,不要盲目跟風(fēng)。在產(chǎn)品功能相對(duì)單一、開(kāi)發(fā)人員較少、并行開(kāi)發(fā)需求不強(qiáng)烈的情況下,推行組件化,不但增加系統(tǒng)復(fù)雜度,而且增加開(kāi)發(fā)人員學(xué)習(xí)成本高,使得開(kāi)發(fā)成本變大,我個(gè)人覺(jué)得這種規(guī)模的應(yīng)用初期需要更多考慮的是如何快速上線、快速迭代和保證App質(zhì)量。因此如果能夠進(jìn)行清晰的分層,嚴(yán)格遵守簡(jiǎn)單統(tǒng)一的架構(gòu)模式即可。組件化比較適合從功能形態(tài)上可以清晰劃分若干模塊的產(chǎn)品,比如美團(tuán)、58同城、淘寶和攜程等產(chǎn)品,內(nèi)部有多個(gè)業(yè)務(wù)模塊,而且這些公司開(kāi)發(fā)此類“航母”App的時(shí)候,會(huì)從組織架構(gòu)把不同業(yè)務(wù)劃分給不同的開(kāi)發(fā)團(tuán)隊(duì),為了能夠保證不同團(tuán)隊(duì)之間能夠獨(dú)立并行開(kāi)發(fā)和發(fā)版,最大程度上減少代碼的依賴程度,這個(gè)時(shí)候應(yīng)用組件化則是最佳實(shí)踐。

上面是對(duì)不要提前過(guò)度優(yōu)化原則的詳細(xì)闡述,并引申到相關(guān)開(kāi)發(fā)領(lǐng)域,做了一些不成熟的探討。下面介紹性能優(yōu)化總體原則的第二個(gè)。

二、要找到性能瓶頸

在做優(yōu)化前,一定要首先找到性能瓶頸有哪些,依性能嚴(yán)重程度逐個(gè)解決。不要盲目?jī)?yōu)化,否則最后可能花了很大的力氣,優(yōu)化掉的可能只是性能損耗很小的一部分。這一原則我覺(jué)得尤為重要,因?yàn)槲以诠ぷ髦杏鲆?jiàn)過(guò)包括我在內(nèi),很多不進(jìn)行性能瓶頸查找,全憑主觀猜測(cè)進(jìn)行性能優(yōu)化的情況。 在尋找性能瓶頸過(guò)程中,也需要注意以下問(wèn)題。

不要主觀猜測(cè),讓性能評(píng)測(cè)數(shù)據(jù)說(shuō)話。

這一點(diǎn)十分重要,要時(shí)刻記住要以事實(shí)說(shuō)話,不要以為某個(gè)函數(shù)使用的算法的時(shí)間復(fù)雜度是O(n2)就覺(jué)得一定會(huì)有性能問(wèn)題,非要費(fèi)很大力氣優(yōu)化到O(n*logn), 殊不知你的輸入數(shù)據(jù)可能只有幾十或者幾百個(gè),即使O(n2)也不會(huì)有多大的性能問(wèn)題。也不要以為某個(gè)方法僅僅調(diào)用了系統(tǒng)庫(kù)的一個(gè)簡(jiǎn)單get方法,就不會(huì)有什么性能問(wèn)題,殊不知這個(gè)get方法里可能包含一些十分耗時(shí)的操作(比如磁盤IO)。因此在遇到性能問(wèn)題的時(shí)候,一定不要憑主觀猜測(cè),實(shí)地跑一下性能數(shù)據(jù),讓數(shù)據(jù)告訴我們性能瓶頸究竟在哪里。

要使用恰當(dāng)?shù)男阅茉u(píng)測(cè)工具。

對(duì)于開(kāi)發(fā)版本的性能優(yōu)化,Xcode提供的instruments絕對(duì)是最好的尋找性能瓶頸的工具,沒(méi)有之一。instruments有豐富的性能評(píng)測(cè)工具,包括常用的Core Animation、Time Profiler、Leaks和Allocations等等。這些工具在分析函數(shù)執(zhí)行時(shí)間、fps和內(nèi)存等方面給我提供了十分便捷的功能。在使用instruments過(guò)程中需要注意:

要使用真機(jī),而不是模擬器。模擬器的CPU比iOS機(jī)器要快很多,所以在模擬器上,CPU相關(guān)的操作會(huì)更快。因?yàn)镸ac的GPU和iOS設(shè)備上的GPU不同,所以模擬器需要在CPU上通過(guò)軟件去模擬iOS設(shè)備上的GPU,所以GPU相關(guān)的操作會(huì)更慢。因此如果使用模擬器去進(jìn)行性能優(yōu)化的話,評(píng)測(cè)設(shè)備和真實(shí)用戶設(shè)備性能表現(xiàn)的不一致,會(huì)導(dǎo)致優(yōu)化的效果大打折扣。這里面內(nèi)存是一個(gè)例外,在做內(nèi)存優(yōu)化的時(shí)候,使用模擬器和真機(jī)一般差別不大,可以使用模擬器進(jìn)行內(nèi)存的優(yōu)化。

要使用Release配置而不是Debug配置,因?yàn)樵趓elease包的時(shí)候,編譯器會(huì)做一些優(yōu)化以提高性能。自己的工程代碼可能也會(huì)在release下做一些優(yōu)化,比如去除log信息和一些debug功能等。我們關(guān)心的是release下的性能,因?yàn)橛脩糇罱K也是使用的release的安裝包。所以測(cè)試的時(shí)候要一定要記住在release配置下進(jìn)行,instruments進(jìn)行性能評(píng)測(cè)的時(shí)候,默認(rèn)是在release下進(jìn)行的。但是工程代碼里面的優(yōu)化則需要自己注意。筆者就曾經(jīng)為此付出過(guò)很大代價(jià),因?yàn)闆](méi)有注意工程代碼里面的一些debug功能,導(dǎo)致優(yōu)化過(guò)程中錯(cuò)誤的認(rèn)為動(dòng)態(tài)庫(kù)是影響啟動(dòng)時(shí)間的罪魁禍?zhǔn)祝撕艽罅獍褎?dòng)態(tài)庫(kù)修改為靜態(tài)庫(kù),白白浪費(fèi)了很多時(shí)間。

要使用性能相對(duì)差的機(jī)器進(jìn)行評(píng)測(cè),因?yàn)槲覀冃枰WC的是我們的應(yīng)用在性能差的機(jī)器上也有良好的表現(xiàn)。如果有條件,最好能夠覆蓋多個(gè)機(jī)型,和我們傳統(tǒng)上的認(rèn)識(shí)不同,機(jī)型越新性能不一定越高,例如iPad3在動(dòng)畫和渲染性能上比iPad2差。

要覆蓋不同系統(tǒng)版本,因?yàn)樵趇OS系統(tǒng)上,一般系統(tǒng)版本越高,同一機(jī)器性能大體上趨于差,所以如果只覆蓋低版本的機(jī)型,可能在高版本上表現(xiàn)的性能會(huì)不盡如人意。

除了使用instruments,還可以使用log等方式進(jìn)行查找性能瓶頸。

對(duì)于線上的App,查找性能瓶頸的工具主要是Application Performance Management(APM)。目前各大公司基本都有自己的APM,主要是對(duì)線上App進(jìn)行性能監(jiān)控以及預(yù)警。因?yàn)樵陂_(kāi)發(fā)和測(cè)試階段,由于使用人數(shù)相對(duì)比較有限,很難覆蓋所有的業(yè)務(wù)場(chǎng)景。而在App發(fā)布出去后,大量用戶在使用過(guò)程中的性能表現(xiàn),會(huì)給我們的App帶來(lái)更全面的性能評(píng)測(cè)數(shù)據(jù),因此線上App的性能監(jiān)控是十分重要的。

要抓重點(diǎn),有的放矢。找到性能損耗大的前N個(gè)問(wèn)題,依重要程度和解決的難易程度解決,這樣才能花最少的精力,解決最大問(wèn)題。

三、要在不同性能指標(biāo)間權(quán)衡,達(dá)到總體最優(yōu)

在已經(jīng)找到性能瓶頸的時(shí)候,解決性能問(wèn)題的方法則需要具體問(wèn)題具體分析,要在不同性能指標(biāo)間權(quán)衡,以達(dá)到總體最優(yōu)。

這需要我們要有整體的意識(shí),App的性能可以分為很多類,不同的性能指標(biāo)對(duì)用戶體驗(yàn)造成的影響也不盡相同,比如fps主要影響的是用戶的滑動(dòng)體驗(yàn),頁(yè)面加載時(shí)間和應(yīng)用啟動(dòng)時(shí)間影響的是用戶等待時(shí)間上的體驗(yàn)。我們?cè)趦?yōu)化的過(guò)程中,要牢記我們的目標(biāo)是希望App的整體體驗(yàn)最優(yōu),而不是某一單項(xiàng)的性能指標(biāo)最優(yōu)。不同優(yōu)化指標(biāo)之間可能是呈正相關(guān),比如優(yōu)化了滑動(dòng)過(guò)程中大量函數(shù)的耗時(shí)時(shí)間,使得fps性能提升,可能會(huì)導(dǎo)致App的耗電量變少。同時(shí),不同優(yōu)化指標(biāo)也可能是負(fù)相關(guān)、相互制約的,比如為了流暢性做了過(guò)多的cache,會(huì)導(dǎo)致內(nèi)存性能下降,甚至導(dǎo)致因?yàn)閙emory warning導(dǎo)致被系統(tǒng)kill掉,這無(wú)疑對(duì)App的整體體驗(yàn)造成了負(fù)面的影響。因此實(shí)際優(yōu)化過(guò)程中需要我們反復(fù)權(quán)衡利弊和取舍,達(dá)到整體的性能最優(yōu)

四、要理解優(yōu)化任務(wù)的底層運(yùn)行機(jī)制

如果不理解優(yōu)化任務(wù)的底層運(yùn)行機(jī)制,可能很難達(dá)到更好的優(yōu)化效果。

比如在做啟動(dòng)時(shí)間優(yōu)化的時(shí)候,如果你不知道iOS中App的啟動(dòng)時(shí)間是由main之前和main之后兩部分時(shí)間組成的,此時(shí)如果你的App是因?yàn)閙ain函數(shù)之前的部分占用了過(guò)多的啟動(dòng)時(shí)間,可能你花了大量的精力去優(yōu)化main之后的時(shí)間卻沒(méi)有達(dá)到好的優(yōu)化效果。如果你不知道App啟動(dòng)過(guò)程的運(yùn)行機(jī)制,就無(wú)法知道去檢查是否鏈接了過(guò)多的自定義的動(dòng)態(tài)庫(kù)或者去load函數(shù)里面確認(rèn)是否有耗時(shí)的操作等等。還有在做fps優(yōu)化的時(shí)候,如果不了解卡頓的底層原因是什么、一個(gè)view從創(chuàng)建到顯示過(guò)程中經(jīng)歷那些步驟、CPU和GPU在這個(gè)過(guò)程中都扮演什么角色,則很難做到絲滑般的順暢?還有在做內(nèi)存優(yōu)化的時(shí)候,如果不了解內(nèi)存分為哪幾類、系統(tǒng)對(duì)App和不同類型extension的內(nèi)存限制機(jī)制的不同、超過(guò)限制系統(tǒng)會(huì)采取什么操作等等,也很難把內(nèi)存優(yōu)化做好。因此只有深入了解底層機(jī)制才能更好的有針對(duì)性的提出更優(yōu)的解決方案。

其實(shí)不只是在性能優(yōu)化方面,在開(kāi)發(fā)過(guò)程中很多情況下,了解底層的原理會(huì)讓你變得更高效,更容易解決遇到的各種問(wèn)題。在這里分享一個(gè)我印象比較深的一次經(jīng)歷。記得有一次在開(kāi)發(fā)某個(gè)功能的時(shí)候,需要用到level db數(shù)據(jù)庫(kù),在開(kāi)發(fā)過(guò)程中做單元測(cè)試的時(shí)候發(fā)現(xiàn),level db的本地存儲(chǔ)文件在不斷刪除和寫入的過(guò)程中,越變?cè)酱螅踔吝_(dá)到1G大小。當(dāng)時(shí)第一印象以為是在使用上出了問(wèn)題,所以上層業(yè)務(wù)邏輯上查找問(wèn)題,結(jié)果查了很久都沒(méi)有找到問(wèn)題。但如果我在使用level db的時(shí)候去多了解一下其底層的實(shí)現(xiàn)原理,了解LSM(Log-Structured-Merge Tree)的原理,遇到這個(gè)問(wèn)題的時(shí)候就不會(huì)認(rèn)為這是一個(gè)bug,也不會(huì)浪費(fèi)了大把的時(shí)間來(lái)做無(wú)用功。所以建議大家不要抱怨每天的工作過(guò)于簡(jiǎn)單枯燥,在開(kāi)發(fā)過(guò)程中多去挖掘一些深層次的東西,不但讓你的技術(shù)的深度不斷加深,也會(huì)對(duì)你的編碼效率有很大的提升。

五、要有技術(shù)保障體系

性能優(yōu)化不能一勞永逸,我個(gè)人覺(jué)得更是一場(chǎng)持久戰(zhàn)。不僅需要你能夠在某個(gè)特定時(shí)期做專項(xiàng)優(yōu)化的攻堅(jiān)戰(zhàn),還要為打好持久戰(zhàn)做出好的后勤補(bǔ)給,為了能使App長(zhǎng)期保持好的性能,不僅僅需要開(kāi)發(fā)人員有良好的開(kāi)發(fā)技能,還需要有一些技術(shù)保障和體系。下面簡(jiǎn)單羅列我能想到的幾個(gè)方面。

要有好的測(cè)試保障,這里的測(cè)試保障不僅僅指的是測(cè)試人員的手動(dòng)測(cè)試,更需要的自動(dòng)化測(cè)試。要建立針對(duì)不同性能指標(biāo)的專項(xiàng)自動(dòng)化測(cè)試,建立一套從定時(shí)運(yùn)行測(cè)試到測(cè)試結(jié)果的輸出等一套完整的自動(dòng)化測(cè)試體系,能夠?yàn)樾阅艿谋WC提供堅(jiān)實(shí)的數(shù)據(jù)支撐。

引入關(guān)鍵性能指標(biāo)上線準(zhǔn)入制度。在開(kāi)發(fā)階段,為了不將有性能問(wèn)題的代碼帶到線上,可以將比如啟動(dòng)時(shí)間、FPS、安裝包大小等指標(biāo)作為關(guān)鍵指標(biāo),上線前進(jìn)行自動(dòng)化測(cè)試,如指標(biāo)不達(dá)標(biāo),不允許上線。

對(duì)于線上App使用APM進(jìn)行監(jiān)控,發(fā)現(xiàn)線上的性能問(wèn)題,有及時(shí)的預(yù)警機(jī)制,能夠隨時(shí)解決線上的性能問(wèn)題。

開(kāi)發(fā)過(guò)程中,代碼中需要有對(duì)性能保障的設(shè)計(jì)。 比如可以設(shè)計(jì)可復(fù)用的高性能控件,這樣其他開(kāi)發(fā)人員在開(kāi)發(fā)類似功能時(shí),可以簡(jiǎn)單復(fù)用,不僅提升了性能,而且大大節(jié)省了開(kāi)發(fā)的時(shí)間。還有比如為了防止App隨著版本迭代導(dǎo)致啟動(dòng)時(shí)加載的服務(wù)越來(lái)約多,導(dǎo)致啟動(dòng)變慢,可以設(shè)計(jì)App啟動(dòng)器,把這些任務(wù)統(tǒng)一放到主界面加載完成后再執(zhí)行,并且在組內(nèi)開(kāi)發(fā)人員中形成硬性的規(guī)范,但凡啟動(dòng)時(shí)期不必須的服務(wù),要么不要執(zhí)行,要么統(tǒng)一放到啟動(dòng)器的主界面加載完成的回調(diào)中執(zhí)行。

定期做一些性能優(yōu)化方面的技術(shù)分享,不僅僅可以提高組內(nèi)同學(xué)的開(kāi)發(fā)技能,還可以活躍組內(nèi)的技術(shù)氣氛。

以上我對(duì)iOS性能優(yōu)化的總體原則做的總結(jié),希望能夠?qū)Υ蠹矣幸稽c(diǎn)點(diǎn)啟示。其中可能很多想法并不成熟,也希望大家能夠多多批評(píng)互相探討,共同進(jìn)步。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,606評(píng)論 6 533
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,582評(píng)論 3 418
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 176,540評(píng)論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 63,028評(píng)論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,801評(píng)論 6 410
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 55,223評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,294評(píng)論 3 442
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 42,442評(píng)論 0 289
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,976評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,800評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,996評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,543評(píng)論 5 360
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,233評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 34,662評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 35,926評(píng)論 1 286
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,702評(píng)論 3 392
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,991評(píng)論 2 374

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,662評(píng)論 25 708
  • 用到的組件 1、通過(guò)CocoaPods安裝 2、第三方類庫(kù)安裝 3、第三方服務(wù) 友盟社會(huì)化分享組件 友盟用戶反饋 ...
    SunnyLeong閱讀 14,639評(píng)論 1 180
  • 去年后半段時(shí)間,陸續(xù)有好友問(wèn)我,還在寫東西嗎。 尷尬,羞愧。 開(kāi)始推公眾號(hào)時(shí),承諾只要沒(méi)什么特殊情況,會(huì)一直更下去...
    唯i閱讀 211評(píng)論 0 0
  • 閨蜜,應(yīng)該是最了解自己,最懂自己,也是最“愛(ài)”自己的人,是會(huì)為對(duì)方著想的人,甚至?xí)榱藢?duì)方的幸福而委屈自己的人。 ...
    子耳子耳閱讀 396評(píng)論 0 1
  • 1、 再一次拿起了這本書,第一次失戀為心愛(ài)的大男孩而迷失了自己的時(shí)候,我朋友送給了我這本書,她抱著我說(shuō),這本書會(huì)讓...
    Lb難朋友閱讀 575評(píng)論 2 1