良好的用戶體驗須要以下要素:數據庫
電池壽命長。隨着能效下降,電池壽命也會下降。但用戶想讓本身的移動設備全天候待命。緩存
速度快。iOS系統處理複雜操做時仍能提供很好的性能。服務器
響應快。同一時刻消耗太多資源會使UI卡頓,響應用戶速度變慢。網絡
溫度低。app消耗的硬件資源的越多,系統工做越繁重,設備的溫度就會逐漸上升。這時系統會經過一些措施下降設備溫度。併發
iOS運用了不少先進的節能技術確保用戶有很好的用戶體驗,包括軟硬件配合優化、先進的App調度機制、網絡延時操做、任務優先級管理機制等。app
App中很小的低效行爲在整個系統中累加後,會對電池壽命、性能、響應速度和溫度產生明顯的影響。使用蘋果推薦的API,以確保系統能夠正確地判斷如何更好地管理咱們的app和app使用的各類資源。分批、減小網絡操做。儘量避免不須要的UI刷新。功耗大的操做應該在用戶的控制之中。好比,若是用戶正在玩一個視圖很是複雜的大型遊戲,電量消耗很快用戶是能夠理解的。不響應用戶操做時,app儘可能不要執行任何操做。框架
基本概念less
沒有一勞永逸地解決能耗問題的方案。不少技術和操做影響着電量的使用:異步
CPU。 CPU是電能消耗大戶,高CPU使用量會迅速消耗掉用戶的電池電量。app作的每件事幾乎都須要用CPU,因此使用CPU要精打細算,真正有須要時經過分批、定時、有序地執行任務。函數
設備喚醒。iOS設備經過睡眠來節能。只要設備被喚醒,屏幕和其餘的硬件資源就必須通電,會產生很高的間接功耗。如非必須,app要儘可能保持閒置,不要推送消息或用其餘方式喚醒設備,特別是app在後臺的時候。
網絡操做。大多數app都須要網絡操做。網絡通訊時,蜂窩數據和Wi-Fi等元器件開始工做就會消耗電能。分批傳輸、減小傳輸、壓縮數據、恰當地處理錯誤,你的app省電效果會很顯著。
圖像、動畫、視頻。app內容每次更新到屏幕上都須要消耗電能處理像素信息。動畫和視頻格外耗電。不經意的或者沒必要要的內容更新一樣會消耗電能,因此UI不可見時,應該避免更新其內容。
位置。不少app爲了記錄用戶的活動或者提供基於位置的服務會進行定位。定位精度越高,定位時間越長,消耗電量也就越多。因此app應該儘可能下降定位精度、縮短定位時間。不須要位置信息以後當即中止定位。
動做傳感器。長時間用不上加速度計、陀螺儀、磁力計等設備的動做數據時,應該中止更新數據,否則也會浪費電能。應按需獲取,用完即停。
藍牙。藍牙活動頻度過高會消耗電能,應該儘可能分批、減小數據輪詢等操做。
簡化、有序地工做
減小後臺工做
實現UIApplicationDelegate中的方法,應用進入後臺前作好暫停任務,保存數據等工做。若是確實須要完成用戶執行的一些任務,應該調用UIApplicationDelegate中的beginBackgroundTaskWithExpirationHandler: 方法,這樣後臺任務能夠繼續執行幾分鐘。任務執行完畢後必定要調用endBackgroundTask:方法,不要等着系統強行掛起進程。
iOS8以後,系統引入了CPU監控機制,以觀察後臺app的CPU使用量是否超過了限制,若是超出限制,進程可能會被關閉。大多數狀況下正常的後臺任務不會遇到這種狀況,若是遇到了能夠查看崩潰日誌信息,異常類型爲EXC_RESOURCE,子類型爲CPU_FATAL。
用QoS分級有序工做
多個app和衆多操做須要共享CPU、緩存、網絡等資源,爲了保持高效,系統須要根據不一樣任務的優先級智能地管理這些工做。好比更新UI這種重要的事須要多分配資源,而一些後臺任務能夠延遲一些執行。服務質量(quality of service, 如下簡稱QoS, iOS8引入)級別能夠經過NSOperation, NSOperationQueue, NSThread objects, dispatch queues, 和pthreads (POSIX threads)指定工做的優先級。有4種QoS級別(和2種特殊的級別),如表2所示,劃線的兩個特殊的級別通常不該該使用,僅做了解便可。最好狀況是,用戶不交互的時候,90%以上的時間讓app運行在Utility或更低級別。
原來GCD中的全局併發隊列(global_queue)用高、默認、低、後臺來指定隊列的優先級。如今應該改用QoS,二者的對應關係如表。
少使用定時器
app常常濫用定時器。想一下你app中的定時器,是否真的有必要存在。拋開具體場景不說,若是定時器觸發太頻繁,能耗影響是比較大的。
用事件通知代替定時器。有些app用定時器監控文件內容、網絡或者其餘狀態的變化,這會致使CPU沒法進入閒置狀態而增長功耗。建議使用事件通知來代替定時器,好比使用dispatch source監測文件變化。對於系統提供的服務,儘可能使用事件通知,表是常見的系統通知和對應的監測方法。
GCD裏的dispatch queues、dispatch semaphores等同步工具比定時器效率高不少,儘可能不要用定時器作同步工具。
全部須要指定一個最後期限的函數或方法都屬於定時器,好比:
1. 高級定時器包括dispatch timer sources、CFRunLoopTimerCreate和其餘CFRunLoopTimer函數、NSTimer、performSelector:withObject:afterDelay:方法。
2. 底層定時器包括sleep, usleep, nanosleep, pthread_cond_timedwait, select, poll, kevent, dispatch_after, dispatch_semaphore_wait。
若是必定要用定時器,儘可能高效地使用,能夠參照下列指導方針:
1. 設置一個合適的超時時間。
2. 再也不須要時及時關閉重複性定時器。
3. 設置觸發公差。
優化I/O訪問
app每次執行I/O任務,好比寫文件,會致使系統退出閒置模式。並且寫入緩存格外耗電。經過下列方法能夠提升能效、改善app性能。
1. 減少寫入數據。數據有變化再寫文件,儘可能把多個更改攢到一塊兒一次性寫入。若是隻有幾個字節的數據改變,不要把整個文件從新寫入一次。若是你的app常常要修改大文件裏不多的內容,能夠考慮用數據庫存儲這些數據。
2. 避免訪問存儲頻度過高。若是app要存儲狀態信息,要等到狀態信息有變化時再寫入。儘可能分批修改,不要頻繁地寫入這些小變更。
3. 儘可能順序讀寫數據。在文件中跳轉位置會消耗一些時間。
4. 儘可能從文件讀寫大數據塊,一次讀取太多數據可能會引起一些問題。好比,讀取一個32M文件的所有內容可能會在讀取完成前觸發內容分頁。
5. 讀寫大量重要數據時,考慮用dispatch_io,其提供了基於GCD的異步操做文件I/O的API。用dispatch_io系統會優化磁盤訪問。
6. 若是你的數據由隨機訪問的結構化內容組成,建議將其存儲在數據庫中,可使用SQLite或Core Data訪問。特別是須要操做的內容可能增加到超過幾兆的時候。
7. 瞭解系統如何緩存文件、如何優化緩存的使用。若是你不打算屢次引用某些數據,不要本身緩存數據。
低電量模式
iOS9以後,iPhone增長了低電量模式,用戶若是但願延長iPhone電池的壽命,能夠在設置 > 電池中開啓該功能。開啓該功能以後iOS會採起一些措施,好比:
1. 下降CPU和GPU性能
2. 暫停隨意的和後臺的活動,包括網絡
3. 下降屏幕亮度
4. 縮短自動鎖屏時間
5. 關閉郵件刷新
6. 關閉視角縮放
7. 關閉動態壁紙
你的app也應該作一些事情幫助系統節省電能,好比,能夠減小動畫、下降幀率、中止位置更新、關閉同步和備份功能等等。能夠經過向NSNotificationCenter註冊NSProcessInfoPowerStateDidChangeNotification 通知監聽低電量模式狀態。
網絡操做
只要app一執行網絡操做,就會產生大量間接能耗(overhead cost)。網絡硬件,好比蜂窩數據和Wi-Fi電路,爲了省電默認是不通電的。爲了執行網絡操做,這些資源必須通電,以後爲了等待接下來可能出現的任務,它們在操做完成後會繼續保持一段時間的活躍。零散的網絡傳輸會致使很高的間接能耗,迅速消耗電池電量
縮減網絡請求
1. 減小、壓縮網絡數據。能夠下降上傳或下載的多媒體內容質量和尺寸等。
2. 使用緩存,不要重複下載相同的數據。
3. 使用斷點續傳,不然網絡不穩定時可能屢次傳輸相同的內容。
4. 網絡不可用時不要嘗試執行網絡請求,儘可能只在Wi-Fi狀況下聯網。
5. 讓用戶能夠取消長時間運行或者速度很慢的網絡操做,設置合適的超時時間。
6. 網絡請求失敗後用SCNetworkReachability的通知監測網絡狀態,網絡可用後再重試。
延遲聯網
分批傳輸。好比,下載視頻流時,不要傳輸很小的數據包,直接下載整個文件或者一大塊一大塊地下載。若是提供廣告,一次性多下載一些,而後再慢慢展現。若是要從服務器下載電子郵件,一次下載多條,不要一條一條地下載。
網絡操做能推遲就推遲。若是經過HTTP上傳、下載數據,建議使用NSURLSession中的後臺會話,這樣系統能夠針對整個設備全部的網絡操做優化功耗。將能夠推遲的操做盡可能推遲到設備充電狀態而且鏈接Wi-Fi時進行,好比同步和備份工做。
VoIP類應用應該用PushKit而不是長鏈接。
圖像、動畫、視頻
如下列指導方針優化內容更新:
1. 減小app使用的視圖數量。
2. 減小不透明視圖的使用,好比視圖上顯示一個半透明模糊效果。若是要用不透明效果,避免用在內容頻繁變化的地方。另外,因爲內容變化後背景視圖和半透明視圖必須同時改變,這也會放大功耗。
3. 避免繪製不可見的內容,好比app的內容被其餘視圖遮擋、被剪切(clipped)或者出畫了。
4. 動畫儘量用較低的幀率。好比,高幀率在玩遊戲時有意義,可是菜單畫面可能較低的幀率就夠了。只有對用戶體驗有影響時才使用高幀率。
5. 執行動畫時不要修改幀率。好比,你的app幀率是60fps,整個動畫就保持這個幀率不要變。
6. 避免同時在屏幕上使用多種幀率。好比,你的遊戲人物是60fps,天上的雲彩移動又是30fps,不要出現這種情況,就算提升其中某一個的幀率,也要用相同的幀率。
7. 開發遊戲時使用推薦的framework。這些framework針對性能和功耗是作過優化的:2D遊戲用SpriteKit、3D遊戲用SceneKit、畫面很是逼真的遊戲用Mietal。
全屏播放視頻時iOS能夠經過高效管理各類資源來優化能耗,可是在視頻上下額外添加圖層會影響功耗優化效果。app儘可能不要在全屏視頻上添加額外的圖層(即便是隱藏的圖層)。若是用戶有須要,能夠經過好比單擊這樣的方式來顯示播放控制之類的UI,不須要了之後應該把這些圖層移除掉。
優化定位和動做(Motion)
錯誤使用定位會阻礙設備進入睡眠模式,讓定位硬件部分持續通電而消耗電池電量,這會使用戶體驗變的不好,下面來看一下如何針對功耗優化定位服務。
若是你的app只是須要快速肯定一下用戶的位置,最好用CLLocationManager的requestLocation (iOS9引入)方法。定位完成以後會自動讓硬件斷電。
除了導航,大多數app不須要一直實時更新位置。須要位置服務時開啓一下定位,儘可能多隔一些時間再進行下次位置更新,更新完了以後立刻關掉定位。除非用戶在移動的交通工具裏,不然不頻繁地更新位置通常沒多大問題。
儘可能下降定位精度。iOS設備默認採用最高精度定位,若是你的app不是確實須要米級的位置信息,不要用最高精度(kCLLocationAccuracyBest)或10米左右的精度(kCLLocationAccuracyNearestTenMeters)。通常來講Core Location提供的精度比你設置的要好,好比你設置爲3千米左右的精度,可能會收到100米左右的精度信息。
若是定位精度一直達不到設置的精度時,中止更新位置,稍後再試。
須要後臺更新位置時,儘可能把pausesLocationUpdatesAutomatically設爲YES,若是用戶不太可能移動的時候系統會自動暫停位置更新。
後臺定位時延時更新位置。若是要作一個健身類的軟件追蹤用戶徒步的距離,能夠等用戶移動一段距離或者過一段時間以後再更新位置,這樣可讓系統優化能耗。
合理使用訪問監控(visit monitoring)。訪問監控容許app接收用戶頻繁或長時間訪問的場所的進出通知,好比在家、公司或者去喜歡的咖啡館。
儘可能不要用significant-change位置服務,優先考慮用region monitoring、 visit monitoring。
用戶移動、搖晃、傾斜設備時,會產生動做(motion)事件,這些事件由加速度計、陀螺儀、磁力計等硬件檢測。不須要監測設備方向時中止通知。好比用戶進入一個只須要豎着顯示的畫面,及時把方向改變通知關掉。開啓動做事件前設置一個比較大的更新間隔。
優化通知
儘可能用本地通知(local notification),若是你的app不依賴外部數據,而是須要基於時間的通知,應該用本地通知,可讓設備的網絡硬件休息一下。
遠程推送有兩個級別,一個是當即推送,另外一個是針對功耗優化過的延時推送。若是不是真的須要即時推送,儘可能使用延時推送。
優化藍牙通訊
1. 沒有必要的時候不要掃描藍牙外設。
2. 掃描外設時通常不要用CBCentralManagerScanOptionAllowDuplicatesKey。
3. 只查找你須要的外設服務。外設可能提供不少服務和特性(characteristic),查找外設的時候能夠指定UUID。
4. 不要輪詢設備特性值,用通知監測特徵值的變化。
5. 特性值再也不提供通知或者再也不須要通訊的時候就斷開鏈接。
Apple Watch
Apple Watch有不少節能的特徵,並且watchOS的API也很是高效。可是仍然須要堅持下面的指導方針:
1. 減小iPhone和手錶之間的通訊,分批通訊,用NSURLSession的後臺會話延遲聯網。
2. 去掉沒必要要的內容刷新。
3. 儘可能用暗色,亮色會顯著增長功耗。除了省電,暗色還可讓屏幕邊框和顯示內容融合得更好
4. 縮小媒體數據大小。若是你的app須要從服務器下載圖片,下載適合手錶屏幕尺寸的圖片,不要下載大圖再縮放,這樣網絡和CPU功耗都更高。
5. 少作工做。若是app須要複雜或者大量的處理任務,考慮將其發送給iPhone處理。
監測功耗
測試或者debug你的app時,注意下列狀況:
電池消耗過快
app應該閒置時卻活動
響應慢,UI卡頓
主線程執行大量任務
動畫使用過多
不透明視圖過多
切換應用
內存慢,沒有緩存(Memory stalls and cache misses)
內存警告
Lock contention
頻繁地切換context
過分使用定時器
頻繁繪製屏幕
頻繁或者反覆執行很小數據的I/O操做
很高的通訊間接功耗,好比傳輸零散的小數據包和緩衝
設備不休眠
用Xcode測量功耗
開發app的過程當中是診斷能耗最好的時機。在Xcode中選擇View > Navigators > Show Debug Navigator,這裏提供了不少儀表用於分析功耗。Energy impact能夠查看正在運行的app的功耗,如圖4。
Cost 和 overhead。藍色的是CPU執行任務消耗的電量,紅色的是執行你的app消耗的其餘系統資源電能。
CPU。灰色方塊表示你的app正在使用CPU執行任務。
Network。灰色方塊表示你的app正在進行網絡操做。
Location。灰色方塊表示你的app正在使用位置服務。
GPU。灰色方塊表示你的app正在使用GPU執行圖像相關操做,好比繪圖或者播放動畫。
Background。灰色方塊表示你的app處於後臺狀態,可是讓系統仍然保持喚醒狀態。
和用戶交互時功耗應該比用戶選擇一個複雜的操做時低,不交互時不該該有功耗。
使用Instruments以前應該先考慮用Xcode中的儀表檢查功耗問題。
用Instruments檢測功耗
1. 啓動Instruments,選擇你的設備和要檢測的app,打開Energy Log,如圖5。推薦使用無線方式鏈接設備,這樣能夠徹底模擬使用電池工做的真實場景。將設備和Mac用數據線鏈接好,在圖5頁面按住?選擇設備,會出現帶有Wireless後綴的設備。
2. 點擊Record按鈕或者按⌘+R,開始記錄。
3. 在設備上正常使用app,這時會記錄功耗數據。
4. 點擊Stop按鈕或按⌘+R,完成記錄。
查看記錄的數據有沒有異常或者能夠優化的地方,如圖6。
提示:app能耗偶爾比較高不必定是app的問題,可能當時的操做自己就很耗電,好比說執行網絡操做的時候使用GPS。你應該關注的是峯值、出乎意料的高功耗區域和其餘能夠優化的地方。
用iOS設備直接記錄功耗
不用有線或無線方式鏈接Instruments,直接用iOS設備記錄功耗能夠得到更真實的數據。記錄工做幾乎不耗電,能夠全天候使用,即便設備進入睡眠模式也會持續記錄。可是若是設備關機後,數據可能會丟失。
在設備上進入設置 > 開發者 > Logging.
開啓功耗記錄,如圖7。
點擊Start Recording按鈕。
正常使用設備。
設備記錄完成後返回圖6所示頁面,點擊Stop Recording.
在Instruments中選擇好設備,進入Energy Log.
選擇File > Import Logged Data from Device。
使用其餘模板和儀器檢測功耗
有不少因素會影響app的功耗,Engergy Log這個模板能夠分析一部分因素,你還能夠用其餘的模板或工具檢查app對功耗的影響。
Activity Monitor. 查看CPU、I/O、網絡使用。
Core Animation. 測量圖像性能和CPU使用量。
GPU Driver. 測量GPU驅動數據。
Location Energy Impact. 測量Core Location對能耗的影響。
Metal System Trace. 經過追蹤app、驅動、GPU的數據,檢測iOS Metal應用的性能。
Network. 分析TCP/IP 和UDP/IP 鏈接。
Time Profiler. 該工具檢測app正在運行的線程,隔一段時間採樣一次。每一個採樣都有完整的調用棧(backtrace),你能夠找出你的代碼中哪裏耗費了大量時間。
自定義模板。上面的模板或儀器能夠分析app的多個方面。若是你想查看特定的幾個方面,能夠向Instruments中添加單個的儀器。若是之後可能還要用相同的分析類型,能夠把你配置的工具保存成模板。
測試性能
app的性能降低會致使功耗增長,能夠用Xcode中的XCTest框架測試你的代碼。代碼會在性能測試的block中連續運行10次,並給出運行平均時間的標準差。