27. SDWebImage是怎么做緩存的?
- 首先說,緩存采用了二級 緩存策略。 圖片緩存的時候, 在內存有緩存, 在磁盤中也有緩存, 其中內存緩存是用NSCache做的 (下面會有NSCache的說明)。
一、如何做緩存的步驟:
0、下載圖片
1、將圖片緩存在內存中
2、判斷圖片的格式png或jpeg,將圖片轉成NSData數據
3、獲取圖片的存儲路徑, 其中圖片的文件名是通過傳入Key經過MD5加密后獲得的
4、將圖片存在進磁盤中。
二、如何獲取圖片的?
1、在內存緩存中找
2、如果內存中找不到, 會去默認磁盤目錄中尋找, 如果找不到,在去自定義磁盤目錄中尋找
3、如果磁盤也找不到就會下載圖片
4、獲取圖片數據之后, 將圖片數據從NSData轉化UIImage。其中轉化根據圖片的類型進行轉化
5、默認對圖片進行解壓縮,生成位圖圖片
6、將位圖圖片返回
三、圖片是如何被解壓縮的?
1、判斷圖片是否是動態圖片,如果是,不能解壓縮
2、判斷圖片是否透明,如果是,不能解壓縮
3、判斷圖片的顏色空間是不是RGB如果不是、不能解壓縮
4、根據圖片的大小創建一個上下文
5、將圖片繪制在上下文中
6、從上下文中讀取一個不透明的位圖圖像,該圖像就是解壓縮后的圖像
7、將位圖圖像返回
接上說 NSCache
- 這個NSCache說白了就是做緩存專用的一個系統類
- 類似可變字典一樣,但是NSCache是線程安全的, 系統類自動做好了加鎖和釋放鎖等一系列的操作, 還有一個重要的是如果內存不足的時候NSCache會自動釋放掉存儲的對象,不需要開發者手動干預。
- 來看一眼NSCache提供的屬性和相關方法
//名稱
@property (copy) NSString *name;
//NSCacheDelegate代理
@property (nullable, assign) id<NSCacheDelegate> delegate;
//通過key獲取value,類似于字典中通過key取value的操作
- (nullable ObjectType)objectForKey:(KeyType)key;
//設置key、value
- (void)setObject:(ObjectType)obj forKey:(KeyType)key; // 0 cost
/*
設置key、value
cost表示obj這個value對象的占用的消耗?可以自行設置每個需要添加進緩存的對象的cost值
這個值與后面的totalCostLimit對應,如果添加進緩存的cost總值大于totalCostLimit就會自動進行刪除
感覺在實際開發中直接使用setObject:forKey:方法就可以解決問題了
*/
- (void)setObject:(ObjectType)obj forKey:(KeyType)key cost:(NSUInteger)g;
//根據key刪除value對象
- (void)removeObjectForKey:(KeyType)key;
//刪除保存的所有的key-value
- (void)removeAllObjects;
/*
當NSCache緩存的對象的總cost值大于這個值則會自動釋放一部分對象直到占用小于該值
非嚴格限制意味著如果保存的對象超出這個大小也不一定會被刪除
這個值就是與前面setObject:forKey:cost:方法對應
*/
@property NSUInteger totalCostLimit; // limits are imprecise/not strict
/*
緩存能夠保存的key-value個數的最大數量
當保存的數量大于該值就會被自動釋放
非嚴格限制意味著如果超出了這個數量也不一定會被刪除
*/
@property NSUInteger countLimit; // limits are imprecise/not strict
/*
這個值與NSDiscardableContent協議有關,默認為YES
當一個類實現了該協議,并且這個類的對象不再被使用時意味著可以被釋放
*/
@property BOOL evictsObjectsWithDiscardedContent;
@end
//NSCacheDelegate協議
@protocol NSCacheDelegate <NSObject>
@optional
//上述協議只有這一個方法,緩存中的一個對象即將被刪除時被回調
- (void)cache:(NSCache *)cache willEvictObject:(id)obj;
@end**
countLimit注意一下這個屬性, 這個屬性就是設置最大緩存數量,啥意思呢? 這玩意就和棧差不多, 先進先出(叫什么FIFO?)原則。比如你countLimit設置為5 那么當你緩存第6個對象的時候, 原本第一個就被移除了。 所以這便就有有一個風險,也可能會是面試點,為什么,通過key去取值的時候,一定要判斷一個獲取的對象是否為nil?答:就因為很有可能某些對象被釋放(頂)掉了。
又又又可能出現的面試題!NSCache里面緩存的對象,在什么場景下會被釋放?
- 回答之前,先說一情況,在某C中創建了NSCache對象,點擊手機的Home或者任何方式進入后臺,會發現NSCache中的代理方法被執行了,于是NSCache對象會釋放掉所有對象,還有的是,如果發生內存警告也會釋放掉所有對象。所以, 這道題應該如下這么回答!
- NSCache自身釋放了,其中存儲的對象也就釋放了。
- 手動調用釋放方法removeObjectForKey、removeAllObjects
- 緩存對象個數大于countLimit
- 緩存總消耗大于totalCostLimit
- 程序進入后臺
- 收到內存警告
28.SDWebImage實現原理是什么? 它是如何解決tableView的復用時出現圖片錯亂問題的呢
- 原理如上,
- 錯亂是在UIImageView+WebCache文件中這個方法每次都會調用 [self sd_cancelCurrentImageLoad];
29. 為什么刷新UI要在主線程操作
UIKit并不是一個線程安全的類,所以涉及多個線程同時對UI進行操作會造成影響。
為什么不把UIKit框架設置為線程安全呢?
因為線程安全需要加鎖,我們都知道加鎖就會消耗性能,影響處理速度,影響渲染速度,我們通常自己在寫@property時都會寫nonatomic來追求高性能高效率。
假設能夠異步設置view的屬性,那我們究竟是希望這些改動能夠同時生效,還是按照各自runloop的進度去改變這個view的屬性呢?
假設UITableView在其他線程去移除了一個cell,而在另一個線程卻對這個cell所在的index進行一些操作,這時候可能就會引發crash。
如果在后臺線程移除了一個view,這個時候runloop周期還沒有完結,用戶在主線程點擊了這個“將要”消失的view,那么究竟該不該響應事件?在哪條線程進行響應?
在Cocoa Touch框架中,UIApplication初始化工作是在主線程進行的。而界面上所有的視圖都是在UIApplication 實例的葉子節點(內存管理角度),所以所有的手勢交互操作都是在主線程上才能響應
30. RunTime
類的結構體:
//Class也表示一個結構體指針的類型
typedef struct objc_class *Class;
struct objc_class {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class _Nullable super_class OBJC2_UNAVAILABLE;
const char * _Nonnull name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE;
struct objc_ivar_list * _Nullable ivars OBJC2_UNAVAILABLE;
struct objc_method_list * _Nullable * _Nullable methodLists OBJC2_UNAVAILABLE;
struct objc_cache * _Nonnull cache OBJC2_UNAVAILABLE;
struct objc_protocol_list * _Nullable protocols OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;
分類結構體
struct category_t {
const char *name;
classref_t cls;
struct method_list_t *instanceMethods; // 對象方法
struct method_list_t *classMethods; // 類方法
struct protocol_list_t *protocols; // 協議
struct property_list_t *instanceProperties; // 屬性
// Fields below this point are not always present on disk.
struct property_list_t *_classProperties;
method_list_t *methodsForMeta(bool isMeta) {
if (isMeta) return classMethods;
else return instanceMethods;
}
property_list_t *propertiesForMeta(bool isMeta, struct header_info *hi);
};
引申1. class_copyIvarList與class_copyPropertyList的區別?
- 1.class_copyIvarList:能夠獲取.h和.m中的所有屬性以及大括號中聲明的變量,獲取的屬性名稱有下劃線(大括號中的除外)。
- 2.class_copyPropertyList:只能獲取由property聲明的屬性,包括.m中的,獲取的屬性名稱不帶下劃線。
引申2. class_ro_t和class_rw_t的區別?
- class_rw_t提供了運行時對類拓展的能力,
- class_ro_t存儲的大多是類在編譯時就已經確定的信息。
- 二者都存有類的方法、屬性(成員變量)、協議等信息,不過存儲它們的列表實現方式不同。簡單的說class_rw_t存儲列表使用的二維數組,class_ro_t使用的一維數組。
- class_ro_t存儲于class_rw_t結構體中,是不可改變的。保存著類的在編譯時就已經確定的信息。
- 運行時修改類的方法,屬性,協議等都存儲于class_rw_t中
31. NSNotification
- NSNotificationCent 子線程中發出通知,也要在主線程中刷新UI
// 比如
dispatch_async(dispatch_get_main_queue(), ^{
// 刷新UI
});
- NSNotificationCenter用完之后不移除, 會崩潰么?
- 有時候會導致crash。比如在通知事件中處理數據或者UI事件,但是由于通知的不確定性造成事件的不確定,有異步操作在通知事件中處理等都可能造成崩潰。
- 而且通知的崩潰很難檢測。
32. 什么情況使用 weak 關鍵字,相比 assign 有什么不同?(輪回系列)
- weak 這個詞兒解決了一件事情,就是內存的事情
- 在ARC中weak的出現解決了一些循環引用的問題, 比如delegate, xib連線出來的控件一般也是weak(也可以用strong )
- weak表明了一種“非擁有的關系”,不保留新值,也不釋放舊值。
- assign也是如此,但常用的assign一般用于基本數據類型(CGFloat 或 NSlnteger等)
- assign可以用于非OC對象,也可以用于OC對象(MRC時代使用), 但是weak必須用在OC對象。
引申 1.關鍵字copy 的用法?
- block用Copy是MRC時代留下來的傳統。在MRC中方法內部的block是在棧區的, 使用copy可以把它放到堆區。 在ARC中寫不寫都行,用Strong也是可以的。
- NSString、NSArray、NSDictionary也經常使用copy, 因為里面有對應的可變的子類型,為了確保安全性, 建議使用copy修飾
引申 2.@property 的本質是什么?ivar、getter、setter 是如何生成并添加到這個類中的。
- @property = ivar(實例變量) + getter + setter
- 自動合成
33. 說說內存管理?
- 其實遇到這道題,挺糾結的,有些TMD面試官就是習慣搞人,從這個玩意里面 能往死給你嗑! 你要看過相關內存管理的詳細原理,你會發現這里面的C++操作很多,沒學過C++的人能看個八九不離十,可是也只是能說個大其概,但是內部細節還是得用C++來說,廢話不多說, 直接上說所謂得面試答案。
- 粗糙版本這么回答,
- 版本一: 內存中每一個對象都有一個屬于自己的引用計數器。當某個對象A被另一個對象引用時,A的引用計數器就+1,如果再有一個對象引用到A,那么A的引用計數器就再+1。當其中某個對象不再引用A了,A的引用計數器會-1。直到A的引用計數減到了0,那么就沒有人再需要它了,就是時候把它釋放掉了
- 版本二:對象通過 alloc copy new 生成得得對象在MRC年代需要手動管理內存, 利用得技術是returnCount引用計數器,來管理對象得釋放時機,alloc創建對象引用計數器 + 1, retain持有關系 引用計數器 +1,release 引用計數器 - 1。 如果當前對象得returnCount = 0 對象就會被在dealloc方法里面適當時機進行釋放(啥時候釋放?)如果當前returnCount大于0得時候,就會一直被持有。
- 稍微詳細版本的,首先當 alloc copy new 生成得對象里面 在內部底層源碼也同時和當前對象相關聯得SideTable, 其內部有三個屬性, 一個是一把自旋鎖,一個是引用計數器相關,一個是維護weak生命得屬性得表, 其中retain、release 對利用鍵值對會對當前對象得引用計數器進行加減操作(位移),如果當前引用計數器為0得時候,其dealloc內部會刪除當前的引用計數器,并且釋放當前對象。
- 詳情請查看http://www.lxweimin.com/p/ef6d9bf8fe59
雜項
1、imageName與imageWithContentsOfFile區別?
imageWithContentsOfFile: 加載本地目錄圖片,并不會緩存,占用內存小, 不能加載image.xcassets里面的圖片資源。 相同的圖片會被重復加載到內存中
imageName:加載到內存中, 會緩存起來, 占用內存較大,相同的圖片不會被重復加載到內存當中,會讀取image.xcassets的圖片圖片資源。
如果不斷重復讀取同一個圖片,則使用imageName
如果不需要重復讀取同一個圖片,并且需要低內存,則使用imageWithContentsOfFile
2.IBOutlet連出來的視圖屬性為什么可以被設置成weak?
因為鏈接之Xcode 內部把鏈接的控件 放進了一個_topLevelObjectsToKeepAliveFromStoryboard的私有數組中,這個數組強引用這所有top level的對象 所以用weak也無傷大雅。
- id 為什么不能用點語法?
點語法就是setter和getter方法, 然而id類 無法確定所指的類是什么類型, 尋不到setter個getter方法,id類型的對象 只能用【】方法調用方法
-
4.id和NSObject的區別?
- id是struct objc_object結構體指針,可以指向任何OC對象,當然不包括NSInteger等類型,因為這些數據類型不是OC對象。
另外OC的基類不止有NSObject一個,還有個NSProxy虛類。所以說id類型和NSObject并不是等價的。
-
5 . OC中 Null 與 nil的區別
- NULL是指指針是空值,用來判斷C 指針;
- nil是指一個OC對象(指針)為空;
- Nil是指一個OC類為空;
- NSNull則用于填充集合元素;這個類只有一個方法null,并且是單例的;
- 6 . 自旋鎖和互斥鎖
- 相同點:都能保證同一時間只有一個線程訪問共享資源,都能保證系統安全
- 不同點:
互斥鎖:如果共享數據已經有了其他線程加鎖了,線程會進行休眠狀態等待鎖,一旦被訪問的資源被解鎖,則等待資源的線程會被喚醒。信號量dispatch_semaphore 為互斥鎖 @synchronized是NSLock的封裝 屬于互斥鎖 互斥鎖一般用于等待時間較長的情況
**適用于**:線程等待鎖的時間較長
自旋鎖:如果共享數據已經有其他線程加鎖了,線程會以死循環的方式等待鎖,一旦被訪問的資源被解鎖,則等待資源的線程會立即執行。OSSpinLock 屬于自旋鎖 自旋鎖一般用于時間較短的情況,OSSpinLock
**適用于**:線程等待鎖的時間較端
7 . 進程和線程的區別
進程是指在系統中正在運行的一個應用程序
線程是進程中的一個實體,一個進程想要執行任務, 必須至少有一條線程,應程序啟動的時候會默認開啟一條線程,也就是主線程
一個進程擁有多個線程
-
8 LayoutSubviews和drawRect調用時機
LayoutSubviews調用時機- init初始化不會調用LayoutSubviews方法
- addsubView 時候會調用
- 改變一個View的frame的時候調用
- 滾動UIScrollView導致UIView重新布局的時候會調用
- 手動調用setNeedsLayout或者layoutIfNeeded
drawRect調用時機
- drawRect 掉用是在Controller->loadView, Controller->viewDidLoad 兩方法之后掉用的.所以不用擔心在 控制器中,這些View的drawRect就開始畫了.、
- 9 cocoaPods里面pod install和update的區別?
**pod install **
- 一般是第一次想要為項目添加pod的時候使用的,當然也可以在添加和移除庫使用
- 每次pod install的時候,pod install 回為每一個安裝的pod庫在Podfile.lock文件中寫入其版本號,并且鎖定當前版本號。
- 如果pod install的時候,不會更新其版本庫,而是去下載新的或者移除當前版本
pod update- 當執行了pod update的時候,cocoaPods不會考慮Podfile.lock中的版本。直接去更新當前所有的庫到最新,然后Podfile.lock會更新這一次的版本號。
- 10 frame和masonry哪個性能好?為什么
- 有的相對布局最終都會轉換成Frame絕對布局 中間多了一層轉換的操作
- 11 . iOS從iOS9 - 13的特性
iOS9
從HTTP升級到HTTPS
App瘦身 下面有講 這里不贅述( App瘦身 )
新增UIStackView
iOS10
新增通知推送相關的操作。自定義通知彈窗,自定義通知類型(地理位置,時間間隔,日歷等)
iOS11
無線 調試
齊劉海兒,導航條,安全距離等
iOS12
啟動速度優化
應用啟動速度提升40%
鍵盤響應速度提升50%
相機啟動速度提升70%
iOS13
黑暗模式 詳情請查閱 http://www.lxweimin.com/p/0da3b107f06c
二、App包以及啟動過程
App瘦身
1、App如何瘦身?
- 刪除陳舊代碼、刪除陳舊xib/sb,刪除無用的圖片資源(檢測未使用圖片的工具LSUnusedResources )
- 無損壓縮圖片,本地音視頻壓縮。以直接減少圖片大小
- 使用webP格式的圖片(加載速度比較慢,但可以達到瘦身的效果)
- 減小類名稱的長度(高性能的話可以試一試)
- 減少使用靜態庫
- 一些主題類的東西提供下載功能,不直接打包在應用包里面,按需加載資源
- iOS9 之后的新特性 應用程序切片(App Slicing)、中間代碼(Bitcode)和按需加載資源(On Demand Resources)
Slicing: 這個過程是iOS9出來之后 不需要程序員干預的一個瘦身的過程,簡單來說就是我們再上傳IPA包到iTunes Connect,然后AppStore會對app進行切片,切成特定的機型想要的數據,比如@3x給max用,@2x就自動剔除了。 是一個自動的過程、
Bitcode:是一種中間碼,如果配置了Bitcode(Xcode7以后默認開啟)的程序會在App Store Connect上被重新編譯等一系列操作,進而蘋果內部會對可執行文件進行優化,也就是說不需要我們干預什么東西,也操作不了, 如果后面蘋果有更牛逼的優化操作,也是蘋果的事情, 跟我們個人開發者一毛錢關系沒有。
On Demand Resources 按需加載, 是程序員自己手動操作,說白了就是在用的時候去下載某些資源, 但是我們自己在配置的時候都需要配置,要額外寫一些代碼啥的,等我們提交到市場的時候, 蘋果內部會把我們按需加載的資源從包里面做了一些抽離操作啥的, 讓我們的包在下載的時候更小,舉個例子,就是吃雞里面沙漠地圖如果玩家不自己下載, 就玩不了沙漠。
on-demond resource(ODR)具體請查看原理版本:http://www.lxweimin.com/p/bacedd8a3ad8
或者詳細使用版本:http://www.cocoachina.com/articles/12155
關于 slicing, bitcode, on-demond resource(ODR)的參考資源https://blog.csdn.net/zhuod/article/details/70051514?utm_source=blogxgwz6
2、app啟動時候都經歷了什么?
啟動分為兩種。 一種是之前啟動過,按了一下home鍵,然后再點啟動,這個啟動叫熱啟動,另外就是第一次啟動app,或者啟動殺死之后的app 叫做冷啟動
根據info.plist里面的設置加載,建立沙箱,權限檢查等
加載可執行文件
加載動態庫
objc運行時的初始化處理(類的注冊,category注冊,selector唯一性檢查等等)
初始化,包括+load方法
執行main函數
Application 初始化,到 applicationDidFinishLaunchingWithOptions 執行完
渲染屏幕,到viewDidAppear 執行完畢,展現給用戶
- mian之前
根據info.plist里面的設置加載,建立沙箱,權限檢查等
加載可執行文件
加載動態庫
objc運行時的初始化處理(類的注冊,category注冊,selector唯一性檢查等等)
初始化,包括+load方法
- mian之后
- 如圖
- 加載流程如下:
[圖片上傳失敗...(image-8500a-1597126379928)]
3、優化啟動時間
- 啟動時間是用戶點擊App圖標,到第一個界面展示的時間。
注意:啟動時間在小于400ms是最佳的,因為從點擊圖標到顯示Launch Screen,到Launch Screen消失這段時間是400ms。啟動時間不可以大于20s,否則會被系統殺掉。
- 以main函數作為分水嶺,啟動時間其實包括了兩部分:
- main函數之前(分析并加載動態庫,注冊需要的類(包括系統的類),Category中的方法也會注冊到對用的類中,執行必要的初始化方法( +load方法)等等
- main函數到第一個界面的viewDidAppear:。
- 所以,優化也是從兩個方面進行的,個人建議優先優化后者,因為絕大多數App的瓶頸在自己的代碼里。
mian函數之前的啟動優化
- 減少動態庫的數量(這是目前為止最耗時的了, 基本上占了95%以上的時間)
- 合并動態庫,比如自己寫的UI控件合并成自己的UIKit
- 確認動態庫是optional還是required。如果該Framework在當前App支持的所有iOS系統版本都存在,那么就設為required,否則就設為optional,因為optional會有些額外的檢查
- 合并Category(UIView+Frame,UIView+AutoLayout合并成一個)
- 將不必需在+load方法中做的事情,延時放到+initialize。
mian函數之后的啟動優化
首先分析一下從main函數開始執行,到第一個頁面顯示, 這段時間做了哪些事情
- 執行didFinishLaunchingWithOptions方法
- 初始化Window,初始化基礎ViewContreoller(一般是UINavigationController+UITabViewController)
- 獲取數據(本地和遠程)
- 最后展示給用戶
- 減少創建線程(高性能iOS開發一書中提到,線程不僅僅有創建時的時間開銷,還會消耗內核的內存,即應用的內存空間。 每個線程大約消耗 1KB 的內核內存空間。線程創建的耗時(不包含啟動時間),其區間范圍在 4000~5000 微秒,即 4~5 毫秒。創建線程后啟動線程的耗時區間為 5~100 毫秒,平均大約在 29 毫秒。這是很大的時間開銷,若在應用啟動時開啟多個線程,則尤為明顯。線程的啟動時間之所以如此之長,是因為多次的上下文切換所帶來的開銷。所以線程在開發過程中也避免濫用)
- 合并或者刪減不必要的類(或者分類)和函數objc的類越多,函數越多啟動越慢
- 在設計師可接受的范文盡量使用小的圖片
-
AppDelegate
通常優化的一般來說,還是從AppDelegate先入手優化
didFinishLaunchingWithOptions
applicationDidBecomeActive
優化的核心思想就是,能延時的延時, 不能延時的盡量放到后臺去優化。
- 日志、統計等必須在 APP 一啟動就最先配置的事件。仍然把它留在 didFinishLaunchingWithOptions 里啟動。
- 項目配置、環境配置、用戶信息的初始化 、推送、IM等事件,這些功能在用戶進入 APP 主體的之前是必須要加載完的,把他放到廣告頁面的viewDidAppear啟動。
- 其他 SDK 和配置事件,由于啟動時間不是必須的,所以我們可以放在第一個界面的 viewDidAppear 方法里,這里完全不會影響到啟動時間。
- 每次用NSLog方式打印會隱式的創建一個Calendar,因此需要刪減啟動時各業務方打的log,或者僅僅針對內測版輸出log
- 盡量不要在didFinishLaunchingWithOptions 里面創建和開啟多線程
參考文獻http://www.lxweimin.com/p/f40fdd8799b8
其文章內部作者談到了美團關于啟動優化的相關分析,看似似曾相似,沒記錯的畫《高性能iOS應用開發》這本書就是美團這幾個哥們兒翻譯的吧,實現方式和書中頗為相似。
3、App電量消耗
- 1.定位
- 2.網絡請求
- 3.CPU處理
- 4.GPU處理
- 5.Bluetooth
定位優化
1.盡量不要實時更新
2.定位精度盡量不要太高
網絡優化
1.減少、壓縮網絡數據
2.能使用緩存就使用緩存,減少網絡請求
3.斷點續傳
4.批量傳輸
5.設置適合的超時時間,用戶可以取消耗時的網絡請求
6.網絡不可用時就不要再執行網絡請求了
CPU/GPU優化
相關離屏渲染操作盡量避免
內存管理處理好
使用懶加載
使用繪制
圖片與imageView相同大小避免多余運算
Timer的時間間隔不宜太短,滿足需求即可
線程適量,不宜過多,不要阻塞主線程
適當使用多線程
減少視圖刷新:確保必要的時候才刷新,能刷新1行cell最好只刷新一行;
為了優化耗電我們還可以做:
1.盡量不要使用定時器
2.優化I/O操作(文件的讀寫操作)
2.1最好不要頻繁讀寫小數據,最好批量讀寫
2.2數據量比較大的時候可以考慮使用數據庫
2.3讀寫大量重要數據時,考慮用dispatch_io,其提供了基于GCD的異步操作文件I/O的API。用dispatch_io系統會優化磁盤訪問
高性能iOS應用開發中提到一下幾點
- 1、CPU優化
- 數據處理(例如文本格式優化)
- 待處理的數據大小----更大的顯示屏允許軟件在單個視圖中展示更多的信息,但這也意味著要處理更多的數據
- 處理數據的算法和數據結構
- 執行更新的次數,尤其是在數據更新之后,觸發應用的狀態或者UI進行更新(比如刷新單行cell)
- 服務器中的數據盡量不要在客戶端上處理(例如服務器字符串,在客戶端進行拆分操作)
- 按需加載(例如tableViewcell 不需要一下子全部渲染,快速滑動的時候 過程中的留白處理。)
- 2、網絡
- 在進行網絡請求之前,先檢查是否有網絡連接。(沒網絡的時候,不要請求網絡)
- 避免沒有連接WiFi的情況下進行高帶寬的消耗操作(因為3G、4G等手機網絡耗電量遠大于WIFi信號),例如視頻流在4G或者非Wifi情況下應該給出響應的提示。
- 3、定位
- 盡量不要實時更新
- 定位精度盡量不要太高