主頁 > 移動端開發 > 你可能不知道的iOS性能優化建議(來自前Apple工程師)

你可能不知道的iOS性能優化建議(來自前Apple工程師)

2020-09-11 03:19:34 移動端開發

今天在推特上看到一篇關于性能優化不錯的文章,是前蘋果開發人員寫的,翻譯了一下與大家分享

作為開發人員,良好的性能對于使我們的用戶感到驚喜和喜悅是無價的,iOS用戶具有很高的標準,如果你的應用程式反應很慢或在記憶體壓力下崩潰,他們將停止使用它,或者更糟糕的是,你的評論會很糟糕,

在過去的6年中,我在Apple從事Cocoa框架和第一方應用程式的開發作業,我從事Spotlight,iCloud,應用程式擴展程式的作業,最近從事過Files的作業,

我注意到有一種很容易實作的目標,你可以在20%的時間內獲得80%的性能提升,

這是一份性能提示清單,希望能給你帶來最大的收益:

1. UILabel的成本超出你的想象


在記憶體使用方面,我們傾向于將lables視為輕量級的,最后,它們只是顯示文本,UILabel實際上存盤為位圖,這很容易消耗兆位元組的記憶體,

值得慶幸的是,UILabel的實作很聰明,并且只使用它需要的:

如果label是單色的,UILabel將選擇kCAContentsFormatGray8Uint的calayercontents格式(每像素1位元組),而非單色標簽(例如,要顯示"??是聚會時間了",或多色NSAttributedString)將需要使用kCAContentsFormatRGBA8Uint(每像素4位元組),
單色標簽最多消耗width * height * contentsScale ^ 2 *(每像素1位元組)位元組,而非單色標簽則消耗4倍的:width * height * contentsScale ^ 2 *(每像素4位元組) ,

例如,在iPhone 11 Pro Max上,大小為414 * 100 points的lable最多可消耗:

414 * 100 * 3 ^ 2 * 1 = 372.6kB(單色)
414 * 100 * 3 ^ 2 * 4 =?1.49MB(非單色)
當這些cells進入重用佇列時,一種常見的反模式是使UITableView / UICollectionView cell labels填充文本內容,一旦cells被回收,label的文本值很可能會有所不同,因此存盤它們很浪費,

要釋放潛在的兆位元組記憶體:

如果將label的文本設定為隱藏,則將label的文本設定為nil,僅偶爾顯示它們,
如果label的文本顯示在UITableView / UICollectionView cell中,則將label的文本設定為nil,在:

tableView(_:didEndDisplaying:forRowAt:)
collectionView(_:didEndDisplaying:forItemAt:)

2. 始終從串行佇列開始,僅將并發佇列作為最后的選擇
例如:

常見的反模式是將不會影響UI的塊從主佇列分配到一個全域并發佇列中,

func textDidChange(_ notification: Notification) {
let text = myTextView.text
myLabel.text = text
DispatchQueue.global(qos: .utility).async {
self.processText(text)
}
}

 

如果我們暫停application:

 

??GCD為我們提交的每個塊創建了一個執行緒

當你dispatch_async一個塊到并發佇列時,GCD將嘗試在其執行緒池中找到一個空閑執行緒來運行該塊, 如果找不到空閑執行緒,則必須為作業項創建一個新執行緒,將塊快速分配到并發佇列可能導致快速創建新執行緒,

記住這些:

創建執行緒不是免費的,如果你要提交的作業量很小(<1毫秒),那么在切換執行背景關系,CPU周期和記憶體弄臟方面,創建新執行緒會很浪費,
GCD會很樂意繼續為你創建執行緒,可能導致執行緒爆炸,
通常,你應該始終從數量有限的串行佇列開始,每個串行佇列代表應用程式的子組件(資料庫佇列,文本處理佇列等),對于具有自己的串行調度佇列的較小物件,請使用dispatch_set_target_queue定位子組件佇列之一,

僅當遇到額外的并發可以解決的瓶頸時,才使用自己創建的并發佇列(不使用dispatch_get_global_queue),并考慮使用dispatch_apply,

關于dispatch_get_global_queue的注釋:

從dispatch_get_global_queue獲得的并發佇列不利于將QoS資訊轉發到系統,因此應避免,

有關libdispatch效率更多詳細建議,請查看這個出色的收集,

3. 它可能沒有看起來那么糟糕
因此,你嘗試過盡可能優化記憶體使用率,但是即使如此,使用應用程式一段時間后,記憶體使用率仍然很高,

不用擔心,某些系統組件只有在收到記憶體警告時才會釋放記憶體,

例如,UICollectionView對-didReceiveMemoryWarning(從iOS 13開始)作出反應,在記憶體不足的情況下從記憶體中清除其重用佇列,

模擬記憶體警告:

在iOS模擬器中,使用"模擬記憶體警告"選單項,
在測驗設備上,呼叫私有API(請勿與此一起提交到App Store):

[[UIApplication sharedApplication] performSelector:@selector(_performMemoryWarning)];


4. 避免使用dispatch_semaphore_t等待異步作業
這是一個常見的反模式:

let sem = DispatchSemaphore(value: 0)
makeAsyncCall {
sem.signal()
}
sem.wait()

問題在于,優先級資訊不會傳播到將由makeAsyncCall發起的作業將完成的其他執行緒/行程,并且可能導致優先級倒置:

假設從主佇列呼叫makeAsyncCall會將作業負載分派到QoS QOS_CLASS_UTILITY的資料庫佇列中,
由于makeAsyncCall從主佇列呼叫了dispatch_async,資料庫佇列的QoS將提高到QOS_CLASS_USER_INITIATED,
用信號量阻塞主佇列意味著它被困在等待QOS_CLASS_USER_INITIATED下運行的作業(低于主佇列的QOS_CLASS_USER_INTERACTIVE),因此優先級反轉,
XPC的附帶說明:

如果你已經使用XPC(在macOS上,或者您正在使用NSFileProviderService),并且想要進行同步呼叫,請避免使用信號量,而是使用以下方式將訊息發送到同步代理:

-[NSXPCConnection synchronousRemoteObjectProxyWithErrorHandler:].

5. 不要使用UIView tags
這是一種不好的做法,并表明有代碼異味, 這也不利于性能,

我最近寫過這樣的代碼,一旦點擊一個視圖,便會根據其標簽值更改其子視圖的顏色,

UIKit使用objc_get / setAssociatedObject()實作標簽,這意味著每次你設定或獲取標簽時,你都在進行字典查找,該字典將顯示在Instruments中:

 

 

 

-[UIView tag]在處理觸摸事件時會消耗寶貴的毫秒數,

文章和推特下有意思的討論
文章和推特下有意思的討論,我這里摘取一些,可能也有幫助

1

Steven Fisher:我仍然沒有找到替代4的好方法,我減少了對該模式的使用,以至于它僅在我的測驗工具中使用,但仍然困擾著我,

Xaxxus:PromiseKit,是你的答案,

Rony Fadel:向API提供者索要同步API,使用同步API是你最好的選擇,它將確保QoS傳播,

Daniel Pourhadi:如果說API提供者是Apple,又要等AVAsset屬性填充怎么辦?在后臺執行緒執行緒(相對于主執行緒)中的信號量有害嗎?

Rony Fadel:后臺執行緒上的信號量有什么好處?如果你真的認為使用同步API有好處,請提交錯誤報告, 這是有害的,因為每次你阻塞等待后臺作業的信號時,系統都會丟失QoS傳播資訊, 然后想象一下,主佇列在該后臺佇列上執行dispatch_sync, boost不會一直傳播到執行AVAsset作業的執行緒,因此主佇列會受到影響,

2
Tyler:非常有趣,謝謝你,重新填充cell-我的理解是,collection/table view進入重用池會在大于可見區域的邊界上觸發-這是一種防止重用池抖動的優化,如果我們 clear/load cell可見性,那么我們是否不進行這種優化? 我了解你的建議是解決記憶體問題,但這對提高性能有什么作用? 不幸的是,似乎沒有一種方法可以知道單元何時真正回到重用池中,

Rony Fadel:cells不在視圖中時(通常在滾動時)進入重用佇列,它與記憶體有關(性能的一部分,至少是我們在Apple上的分類方式),但與滾動性能無關,

Tyler:我認為你描述的是在didDisappear時回傳重用池的內容與iOS10之前的行為一致, 他們從iOS 10記錄中的UICollectionView的新增功能中描述了添加的滾動性能優化- “…現在該cell將要退出CollectionView的可見范圍,因此,我們將向其發送期望的didEndDisplayingCell,Peter在談論iOS 9時,此時該cell進入了重用佇列,我們將完成此操作,要再次在此特定cell中顯示資料,我們必須經歷生命周期的開始 并呼叫cellForItemAtIndexPath,但是在iOS 10中,我們將保留該cell的時間稍長一點,” 請注意,我只是想起這一點,因為我只是在這個領域中作業,試圖弄清楚如何避免記憶體不足的情況而不進行此優化,再次感謝你的帖子,

3
John Siracusa:當你要等待超時的異步非主執行緒用戶啟動的作業時,你建議使用什么而不是DispatchSemaphore?

Yaron Inger:你可以使用dispatch group 和 dispatch_group_wait,

Rafael Cerioli:Dispatch groups 和 semaphores一樣,沒有方法將async轉變成sync,

J Matusevich:Dispatch group 是答案,

NieR: Autoconf:Dispatch group 和 semaphore 性能一樣. The API 很棒但行為沒有區別,

Bob Godwin:DispatchWorkItem????它們處理了我必須使用semafores的那些情況, 只是該API尚未為開發人員所廣泛了解 dispatchworkitem,

pkamb:DispatchGroup! Waiting for multiple blocks to finish

推薦??:
如果你想一起進階,不妨添加一下交流群1012951431
面試題資料或者相關學習資料都在群檔案中 進群即可下載!

 

轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/4177.html

標籤:iOS

上一篇:類(元類)物件方法快取原理

下一篇:實作iOS中的多語言切換

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【從零開始擼一個App】Dagger2

    Dagger2是一個IOC框架,一般用于Android平臺,第一次接觸的朋友,一定會被搞得暈頭轉向。它延續了Java平臺Spring框架代碼碎片化,注解滿天飛的傳統。嘗試將各處代碼片段串聯起來,理清思緒,真不是件容易的事。更不用說還有各版本細微的差別。 與Spring不同的是,Spring是通過反射 ......

    uj5u.com 2020-09-10 06:57:59 more
  • Flutter Weekly Issue 66

    新聞 Flutter 季度調研結果分享 教程 Flutter+FaaS一體化任務編排的思考與設計 詳解Dart中如何通過注解生成代碼 GitHub 用對了嗎?Flutter 團隊分享如何管理大型開源專案 插件 flutter-bubble-tab-indicator A Flutter librar ......

    uj5u.com 2020-09-10 06:58:52 more
  • Proguard 常用規則

    介紹 Proguard 入口,如何查看輸出,如何使用 keep 設定入口以及使用實體,如何配置壓縮,混淆,校驗等規則。

    ......

    uj5u.com 2020-09-10 06:59:00 more
  • Android 開發技術周報 Issue#292

    新聞 Android即將獲得類AirDrop功能:可向附近設備快速分享檔案 谷歌為安卓檔案管理應用引入可安全隱藏資料的Safe Folder功能 Android TV新主界面將顯示電影、電視節目和應用推薦內容 泄露的Android檔案暗示了傳說中的谷歌Pixel 5a與折疊屏新機 谷歌發布Andro ......

    uj5u.com 2020-09-10 07:00:37 more
  • AutoFitTextureView Error inflating class

    報錯: Binary XML file line #0: Binary XML file line #0: Error inflating class xxx.AutoFitTextureView 解決: <com.example.testy2.AutoFitTextureView android: ......

    uj5u.com 2020-09-10 07:00:41 more
  • 根據Uri,Cursor沒有獲取到對應的屬性

    Android: 背景:呼叫攝像頭,拍攝視頻,指定保存的地址,但是回傳的Cursor檔案,只有名稱和大小的屬性,沒有其他諸如時長,連ID屬性都沒有 使用 cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATIO ......

    uj5u.com 2020-09-10 07:00:44 more
  • Android連載29-持久化技術

    一、持久化技術 我們平時所使用的APP產生的資料,在記憶體中都是瞬時的,會隨著斷電、關機等丟失資料,因此android系統采用了持久化技術,用于存盤這些“瞬時”資料 持久化技術包括:檔案存盤、SharedPreference存盤以及資料庫存盤,還有更復雜的SD卡記憶體儲。 二、檔案存盤 最基本存盤方式, ......

    uj5u.com 2020-09-10 07:00:47 more
  • Android Camera2Video整合到自己專案里

    背景: Android專案里呼叫攝像頭拍攝視頻,原本使用的 MediaStore.ACTION_VIDEO_CAPTURE, 后來因專案需要,改成了camera2 1.Camera2Video 官方demo有點問題,下載后,不能直接整合到專案 問題1.多次拍攝視頻崩潰 問題2.雙擊record按鈕, ......

    uj5u.com 2020-09-10 07:00:50 more
  • Android 開發技術周報 Issue#293

    新聞 谷歌為Android TV開發者提供多種新功能 Android 11將自動填表功能整合到鍵盤輸入建議中 谷歌宣布Android Auto即將支持更多的導航和數字停車應用 谷歌Pixel 5只有XL版本 搭載驍龍765G且將比Pixel 4更便宜 [圖]Wear OS將迎來重磅更新:應用啟動時間 ......

    uj5u.com 2020-09-10 07:01:38 more
  • 海豚星空掃碼投屏 Android 接收端 SDK 集成 六步驟

    掃碼投屏,開放網路,獨占設備,不需要額外下載軟體,微信掃碼,發現設備。支持標準DLNA協議,支持倍速播放。視頻,音頻,圖片投屏。好點意思。還支持自定義基于 DLNA 擴展的操作動作。好像要收費,沒體驗。 這里簡單記錄一下集成程序。 一 跟目錄的build.gradle添加私有mevan倉庫 mave ......

    uj5u.com 2020-09-10 07:01:43 more
最新发布
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:40:31 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:40:11 more
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:39:36 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:39:13 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:16:23 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:16:15 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:15:46 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:14:53 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:14:08 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:08:34 more