iOS消息高并發(fā)優(yōu)化

本篇文章并不打算過(guò)多的講解技術(shù)實(shí)現(xiàn)的細(xì)節(jié),大部分都是點(diǎn)到為止。我個(gè)人覺(jué)得技術(shù)細(xì)節(jié)雖然很重要,但是它只是實(shí)現(xiàn)一個(gè)功能的手段,更為重要的是實(shí)現(xiàn)功能的思路和方向。只有理清了思路,選定了方向,接下來(lái)的實(shí)現(xiàn)就應(yīng)該是水到渠成了。

好了,下面我們?cè)撜f(shuō)說(shuō)優(yōu)化的事。我們看一下微信,基礎(chǔ)功能就是聊天,能看到經(jīng)常發(fā)生變化的就是消息列表,和聊天時(shí)候的聊天界面了,幾乎只要你在使用它的時(shí)候這兩個(gè)頁(yè)面都會(huì)發(fā)生變化。所以針對(duì)性能上最重要的兩個(gè)界面,一個(gè)是消息列表,一個(gè)是聊天界面。

一.消息列表頁(yè)面的優(yōu)化:

首先我們發(fā)消息時(shí)候觀察一下消息列表的特性,當(dāng)發(fā)送一條消息時(shí)候,消息的數(shù)量會(huì)變化,列表會(huì)出現(xiàn)在最上邊的位置,列表內(nèi)的內(nèi)容會(huì)發(fā)生變化。從消息列表的特性,我們就可以分析出要優(yōu)化的點(diǎn)了。通過(guò)這些點(diǎn),我們做了一些優(yōu)化:

1.如果列表消息從沒(méi)顯示過(guò)需要刷新列表,創(chuàng)建好一個(gè)cell后,將cell插入到第一位上,cell插入的性能要高于刷新tableview的性能。

2.如果消息已經(jīng)顯示過(guò)了,但是并不是第一位,則需要刷新列表。

3.如果消息已經(jīng)顯示,并且是第一位,則只需要cell的內(nèi)容變化。

4.只修改cell里的內(nèi)容,不進(jìn)行刷新cell整體,這里要注意的是,一定要最小化刷新。刷新點(diǎn)越小,性能損耗越小。我們項(xiàng)目架構(gòu)是MVVM,采用了ReactiveCocoa框架,針對(duì)每個(gè)cell上的可變化的控件數(shù)據(jù)進(jìn)行了監(jiān)聽(tīng),每一個(gè)cell上對(duì)應(yīng)一個(gè)vm,這樣當(dāng)vm上的數(shù)據(jù)變化時(shí)候,cell上的數(shù)據(jù)也就跟著變了。做到了最小化刷新。

5.避免使用autolayout計(jì)算位置,這個(gè)很重要,在性能要求高的情況下,autolayout計(jì)算會(huì)很耗時(shí)間,尤其在算tableview高度的時(shí)候可見(jiàn)一斑。可喜的是消息列表的高度是固定的,所以在計(jì)算高度時(shí)候我們并未花費(fèi)時(shí)間。

6.使用(__kindof UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath而不使用-(nullable __kindof UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier來(lái)查找cell,因?yàn)橄逻叺姆椒〞?huì)多查一次,耗時(shí)更長(zhǎng)一點(diǎn)。

7.cellForRowAtIndexPath方法只負(fù)責(zé)創(chuàng)建cell,willDisplayCell方法才給cell進(jìn)行賦值操作。從方法名字就可以看出來(lái)原因

8.當(dāng)來(lái)消息轟炸時(shí)候,必然會(huì)是不同的人發(fā)來(lái)的消息,會(huì)導(dǎo)致tableview不可避免的刷新,如果不加處理必然會(huì)卡頓,要知道,機(jī)器也是有瓶頸的。這里我們做的優(yōu)化是根據(jù)cpu的使用率選擇性的刷新tableview。后來(lái)我們發(fā)現(xiàn)微信也是有這個(gè)現(xiàn)象,并不是實(shí)時(shí)的刷新,我們猜測(cè)也是類似處理。

9.重繪制系統(tǒng)控件,相信你也發(fā)現(xiàn)了消息列表里,主要有兩個(gè)控件,一個(gè)是頭像,一個(gè)是label。而系統(tǒng)的UIImageView用來(lái)顯示頭像,未免有點(diǎn)重。我們的處理是使用UIView,設(shè)置View得layer.content來(lái)處理。針對(duì)layer層做的setImageWithUrl的第三方庫(kù)也不少,大家可以自行查詢。另一個(gè)就是label,如果你能集成UIView自己繪制一個(gè)label,我想也許會(huì)有一點(diǎn)效果。

以上我們對(duì)消息列表做的優(yōu)化,寫的并不全,只記得大概有這些吧。

二.聊天界面的優(yōu)化:

聊天界面的優(yōu)化算是比較繁瑣的了,但是優(yōu)化點(diǎn)跟回話列表的優(yōu)化差不多。上邊提到回話列表里最耗時(shí)的tableview的高度是固定的,而聊天界面的幾乎每條消息的高度都可能不一樣,所以我們?cè)趦?yōu)化聊天界面時(shí)候最重要的一點(diǎn)就是計(jì)算tableviewcell的高度。而我們?cè)谟?jì)算tableview的高度是怎么做的呢?

其實(shí)這個(gè)網(wǎng)上千篇一律的優(yōu)化tableview的方式是大同小異的。

主要有兩個(gè)準(zhǔn)則:

第一個(gè)是能在后臺(tái)線程執(zhí)行的都放在后臺(tái)線程里。

第二個(gè)計(jì)算高度要放在顯示之前。

上邊提到我們使用的ReactiveCocoa基于事件流來(lái)處理消息,這個(gè)確實(shí)是為開(kāi)發(fā)帶來(lái)了很大的好處,處理層次非常清晰,開(kāi)發(fā)效率的提升,代碼復(fù)雜度降低,多人員開(kāi)發(fā)分工分明,低耦合等這些好處充分讓你感受到編程的樂(lè)趣,之后我們會(huì)出一篇關(guān)于架構(gòu)的文章,這里只是稍提一嘴。當(dāng)然即使你不用ReactiveCocoa也沒(méi)關(guān)系,思路都是一樣的。首先是你從底層異步接收到消息,進(jìn)行消息的處理,包括數(shù)據(jù)庫(kù)的處理,提供給View顯示的對(duì)象處理,這里我們是用的VM層,其中也包括了消息的高度的計(jì)算,這些都是放在線程隊(duì)列里,當(dāng)所有的處理完成,然后進(jìn)行主線程消息列表更新,進(jìn)行插入一個(gè)cell和向上滾動(dòng)一條消息的距離。我們之前把VM的創(chuàng)建放在了主線程,發(fā)現(xiàn)在32位機(jī)器上掉了10fps,這是讓人不能忍受的事情。當(dāng)然還有一點(diǎn)是盡量保證你的對(duì)象不要太大,如果太大也會(huì)影響性能,我們的vm就比較大,這也是以后性能上的隱患。優(yōu)化tableView的另外一點(diǎn)就是cell的制作了,要說(shuō)的跟上邊第九條提到的也差不多,這里我也總結(jié)了一下幾個(gè)原則:

1.巧妙的選擇控件。比如上邊提到的,如果只是顯示一個(gè)圖片,那么用View的layer.content性能自然是好一些。圖片加點(diǎn)擊也可以用view,然后監(jiān)聽(tīng)view的touch事件,像button這種重量級(jí)的控件在性能為主的app面前,我對(duì)他們都是棄之如敝履。

2.減少使用layer層的cornerRadius,mask等圓角的繪制,這會(huì)引發(fā)離屏渲染,增加cpu的占用率。如果業(yè)務(wù)需要的話,我們可以通過(guò)UIBezierPath來(lái)drawInRect它。

3.避免設(shè)置透明

4.避免autolayout設(shè)定控件位置

5.盡可能的減少視圖的層級(jí),如果你能把所有的控件都繪制到一個(gè)View上,可想而知性能會(huì)爆棚。

三.其他優(yōu)化

還有兩大優(yōu)化點(diǎn)不容忽視。

一是數(shù)據(jù)持久層的優(yōu)化,就是所謂的數(shù)據(jù)庫(kù)優(yōu)化。

二就是內(nèi)存優(yōu)化。

關(guān)于持久層的優(yōu)化嚴(yán)格來(lái)性能上通常不會(huì)有太大出入,只不過(guò)我們之前是直接針對(duì)底層sqlite數(shù)據(jù)庫(kù)很簡(jiǎn)單的封裝,后來(lái)用了fmdb,發(fā)現(xiàn)在插入性能上有了明顯的提升。幾乎用過(guò)的小伙伴都說(shuō)好。持久化這邊我們將fmdb,jsonModel進(jìn)行封裝了一個(gè)庫(kù),提供了友好的api,通常像這樣使用[message findAll],[message save]等基本上都不需要寫sql語(yǔ)句。回頭我們會(huì)開(kāi)源化。關(guān)于sql優(yōu)化的我們總結(jié)了幾點(diǎn):

1.大批量插入時(shí)候,用事務(wù)可以幾何倍的減少插入時(shí)間,原因是會(huì)把sql都加入內(nèi)存,然后一次性提交。

2.針對(duì)經(jīng)常變化的表、字段避免使用索引,當(dāng)然索引帶來(lái)的查詢性能也是幾何倍的增加,這里要說(shuō)的一點(diǎn)是like并不會(huì)使用到索引

3.巧妙使用sql語(yǔ)句增刪改查,能夠用一條語(yǔ)句解決的事就不要使用兩條,比如之前我們發(fā)現(xiàn)一個(gè)設(shè)置已讀消息,是把這個(gè)人的消息取出來(lái),然后再設(shè)置進(jìn)去,后來(lái)我們直接進(jìn)行了這個(gè)人的update語(yǔ)句,發(fā)現(xiàn)這塊的處理性能高了很多。

4.當(dāng)單條數(shù)據(jù)小于 20K 時(shí),數(shù)據(jù)越小 SQLite 讀取性能越高;單條數(shù)據(jù)大于 20K 時(shí),直接寫為文件速度會(huì)更快一些。

5.ibireme.com提到過(guò)在官網(wǎng)下載源碼編譯的sqlite性能會(huì)高幾倍,我確實(shí)編譯了一下,但是編譯出來(lái)的是dylib,現(xiàn)在的系統(tǒng)是tbd,我沒(méi)轉(zhuǎn)過(guò)去,并且pods里依賴的也是tbd的,所以也就作罷了,主要放棄原因還是發(fā)現(xiàn)我們將很多數(shù)據(jù)庫(kù)操作的部分去掉了,cpu占用率也沒(méi)有發(fā)生變動(dòng)。如果有搞定的同學(xué)記得分享一下。

數(shù)據(jù)庫(kù)的大概能記住的也就這幾點(diǎn)吧。

大最后說(shuō)一嘴,多用Instuments來(lái)檢測(cè)你的方法執(zhí)行時(shí)間,以及CPU GPU占用率,這能夠很好的幫你優(yōu)化你的程序。

最后編輯于
?著作權(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閱讀 230,578評(píng)論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,701評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 178,691評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 63,974評(píng)論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,694評(píng)論 6 413
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 56,026評(píng)論 1 329
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,015評(píng)論 3 450
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 43,193評(píng)論 0 290
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,719評(píng)論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,442評(píng)論 3 360
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,668評(píng)論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,151評(píng)論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,846評(píng)論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 35,255評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 36,592評(píng)論 1 295
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,394評(píng)論 3 400
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,635評(píng)論 2 380

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

  • 概述在iOS開(kāi)發(fā)中UITableView可以說(shuō)是使用最廣泛的控件,我們平時(shí)使用的軟件中到處都可以看到它的影子,類似...
    liudhkk閱讀 9,085評(píng)論 3 38
  • 工作了將近一個(gè)月的nusery里的團(tuán)寵
    M_f7e0閱讀 244評(píng)論 0 0
  • 今天參加老公同學(xué)的婚禮,突然想記錄下這一刻,這時(shí)的心情,突然發(fā)現(xiàn)沒(méi)有地方可以任我書寫,
    小魚愛(ài)喝酸奶閱讀 335評(píng)論 0 0
  • 今天看了幾集《今生是第一次》,覺(jué)得該記錄點(diǎn)啥。故事的開(kāi)始是女主在首爾打拼,到了30歲一事無(wú)成,沒(méi)有房子沒(méi)有愛(ài)情甚至...
    s沈小閱讀 219評(píng)論 0 0
  • 水蕨(Ceratopteris thalictroides),水蕨科水蕨屬的一種蕨,分布在熱帶和亞熱帶地區(qū),我國(guó)湖...
    綠汀閱讀 1,252評(píng)論 2 2