推薦系統直接學習小碼哥iOS底層原理班---MJ老師的課確實不錯,強推一波。ios
顯示器將要展現一頁數據git
按照60FPS的刷幀率,每隔16ms就會有一次VSync信號github
儘可能用輕量級的對象數據庫
好比用不到事件處理的地方,能夠考慮使用CALayer取代UIView緩存
不要頻繁地調用UIView的相關屬性bash
好比frame、bounds、transform等屬性,儘可能減小沒必要要的修改網絡
儘可能提早計算好佈局併發
在有須要時一次性調整對應的屬性,不要屢次修改屬性app
Autolayout會比直接設置frame消耗更多的CPU資源異步
圖片的size最好恰好跟UIImageView的size保持一致
減小ImageView對圖片的伸縮操做
控制一下線程的最大併發數量
儘可能把耗時的操做放到子線程
充分利用多核優點
文本處理(尺寸計算、繪製)
圖片處理(解碼、繪製)
[UIImage imageNamed:@"timg"]
加載出來的圖片是未解碼的,當UIImageView須要被展現的時候纔會由CPU進行解碼操做。而這個解碼操做默認在主線程進行。咱們能夠將解碼操做轉移到異步。
- (void)image
{
UIImageView *imageView = [[UIImageView alloc] init];
imageView.frame = CGRectMake(100, 100, 100, 56);
[self.view addSubview:imageView];
self.imageView = imageView;
dispatch_async(dispatch_get_global_queue(0, 0), ^{
// 獲取CGImage
CGImageRef cgImage = [UIImage imageNamed:@"timg"].CGImage;
// 獲取圖片信息
CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(cgImage) & kCGBitmapAlphaInfoMask;
BOOL hasAlpha = NO;
if (alphaInfo == kCGImageAlphaPremultipliedLast ||
alphaInfo == kCGImageAlphaPremultipliedFirst ||
alphaInfo == kCGImageAlphaLast ||
alphaInfo == kCGImageAlphaFirst) {
hasAlpha = YES;
}
// bitmapInfo
CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host;
bitmapInfo |= hasAlpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst;
// 獲取圖片大小size
size_t width = CGImageGetWidth(cgImage);
size_t height = CGImageGetHeight(cgImage);
// 建立圖形上下文
CGContextRef context = CGBitmapContextCreate(NULL, width, height, 8, 0, CGColorSpaceCreateDeviceRGB(), bitmapInfo);
// 將圖片繪製到上下文中
CGContextDrawImage(context, CGRectMake(0, 0, width, height), cgImage);
// 獲取解碼後的獲取CGImage
cgImage = CGBitmapContextCreateImage(context);
// 將解碼後的CGImage包裝成UIImage
UIImage *newImage = [UIImage imageWithCGImage:cgImage];
// 釋放資源
CGContextRelease(context);
CGImageRelease(cgImage);
// back to the main thread
dispatch_async(dispatch_get_main_queue(), ^{
//回到主線程設置圖片
self.imageView.image = newImage;
});
});
}
複製代碼
On-Screen Rendering:
當前屏幕渲染,在當前用於顯示的屏幕緩衝區進行渲染操做
Off-Screen Rendering:
離屏渲染,在當前屏幕緩衝區之外新開闢一個緩衝區進行渲染操做
當使用某些效果時,圖層的效果處理起來很費時,有可能超過16.67ms致使丟幀。系統會在當前屏幕的緩衝區以外另開闢一個緩衝區去預合成。
在VSync(垂直脈衝)信號做用下,視頻控制器每隔16.67ms就會去幀緩衝區(當前屏幕緩衝區)讀取渲染後的數據;可是有些效果被認爲不能直接呈現於屏幕前,而須要在別的地方作額外的處理,進行預合成。
當使用圓角,陰影,遮罩的時候,圖層屬性的混合體被指定爲在未預合成以前(下一個VSync信號開始前)不能直接在屏幕中繪製,因此就須要屏幕外渲染。
你能夠這麼理解. 老闆叫我短期間內作一個app.我一我的能作,可是時間過短,因此我得讓我朋友一塊兒來幫着我作.(性能消耗: 也就是耗 你跟你朋友之間溝通的這些成本,多浪費啊).可是沒辦法 誰讓你作不完呢.
須要建立新的緩衝區
頻繁的切換緩衝區
離屏渲染的整個過程,須要屢次切換上下文環境,先是從當前屏幕(On-Screen)切換到離屏(Off-Screen);等到離屏渲染結束之後,將離屏緩衝區的渲染結果顯示到屏幕上,又須要將上下文環境從離屏切換到當前屏幕
光柵化
layer.shouldRasterize = YES
遮罩
layer.mask
圓角
同時設置layer.masksToBounds = YES、layer.cornerRadius大於0 考慮經過CoreGraphics繪製裁剪圓角,或者叫美工提供圓角圖片
陰影,layer.shadowXXX
若是設置了layer.shadowPath就不會產生離屏渲染
富文本效果
平時所說的「卡頓」主要是由於在主線程執行了比較耗時的操做
能夠添加Observer到主線程RunLoop中,經過監聽RunLoop狀態切換的耗時,以達到監控卡頓的目的。
一般是監聽Runloop被喚醒到休眠以前這段時間的時長,連續超過閥值必定次數就打印當前主線程的堆棧。
MJ裏的項目是LXDAppFluecyMonitor
儘量下降CPU、GPU功耗
少用定時器
優化I/O操做
儘可能不要頻繁寫入小數據,最好批量一次性寫入
讀寫大量重要數據時,考慮用dispatch_io,其提供了基於GCD的異步操做文件I/O的API。用dispatch_io系統會優化磁盤訪問
數據量比較大的,建議使用數據庫(好比SQLite、CoreData)
減小、壓縮網絡數據
若是屢次請求的結果是相同的,儘可能使用緩存
使用斷點續傳,不然網絡不穩定時可能屢次傳輸相同的內容
網絡不可用時,不要嘗試執行網絡請求
讓用戶能夠取消長時間運行或者速度很慢的網絡操做,設置合適的超時時間
批量傳輸,好比,下載視頻流時,不要傳輸很小的數據包,直接下載整個文件或者一大塊一大塊地下載。若是下載廣告,一次性多下載一些,而後再慢慢展現。若是下載電子郵件,一次下載多封,不要一封一封地下載
若是隻是須要快速肯定用戶位置,最好用CLLocationManager的requestLocation方法。定位完成後,會自動讓定位硬件斷電
若是不是導航應用,儘可能不要實時更新位置,定位完畢就關掉定位服務
儘可能下降定位精度,好比儘可能不要使用精度最高的kCLLocationAccuracyBest
須要後臺定位時,儘可能設置pausesLocationUpdatesAutomatically爲YES,若是用戶不太可能移動的時候系統會自動暫停位置更新
儘可能不要使用startMonitoringSignificantLocationChanges,優先考慮startMonitoringForRegion:
用戶移動、搖晃、傾斜設備時,會產生動做(motion)事件,這些事件由加速度計、陀螺儀、磁力計等硬件檢測。在不須要檢測的場合,應該及時關閉這些硬件
APP的啓動能夠分爲2種
冷啓動(Cold Launch):從零開始啓動APP
熱啓動(Warm Launch):APP已經在內存中,在後臺存活着,再次點擊圖標啓動APP
APP啓動時間的優化,主要是針對冷啓動進行優化
經過添加環境變量能夠打印出APP的啓動時間分析(Edit scheme -> Run -> Arguments) DYLD_PRINT_STATISTICS設置爲1 若是須要更詳細的信息,那就將DYLD_PRINT_STATISTICS_DETAILS設置爲1
total time: 1.4 seconds (100.0%)
total images loaded: 257 (0 from dyld shared cache)
total segments mapped: 764, into 103339 pages with 7230 pages pre-fetched
total images loading time: 720.70 milliseconds (48.1%)
total load time in ObjC: 71.93 milliseconds (4.8%)
total debugger pause time: 539.08 milliseconds (36.0%)
total dtrace DOF registration time: 0.12 milliseconds (0.0%)
total rebase fixups: 2,519,273
total rebase fixups time: 635.12 milliseconds (42.4%)
total binding fixups: 283,078
total binding fixups time: 36.50 milliseconds (2.4%)
total weak binding fixups time: 0.52 milliseconds (0.0%)
total redo shared cached bindings time: 52.57 milliseconds (3.5%)
total bindings lazily fixed up: 0 of 0
total time in initializers and ObjC +load: 31.39 milliseconds (2.0%)
libSystem.B.dylib : 2.92 milliseconds (0.1%)
libBacktraceRecording.dylib : 3.50 milliseconds (0.2%)
CoreFoundation : 1.74 milliseconds (0.1%)
Foundation : 2.02 milliseconds (0.1%)
libMainThreadChecker.dylib : 18.89 milliseconds (1.2%)
total symbol trie searches: 132606
total symbol table binary searches: 0
total images defining weak symbols: 20
total images using weak symbols: 61
複製代碼
APP的啓動由dyld主導,將可執行文件加載到內存,順便加載全部依賴的動態庫
並由runtime負責加載成objc定義的結構
全部初始化工做結束後,dyld就會調用main函數
APP的冷啓動能夠歸納爲3大階段
dyld
Apple的動態連接器,能夠用來裝載Mach-O文件(可執行文件、動態庫等)
裝載APP的可執行文件,同時會遞歸加載全部依賴的動態庫
當dyld把可執行文件、動態庫都裝載完畢後,會通知Runtime進行下一步的處理
runtime
調用map_images
進行可執行文件內容的解析和處理
在load_images中調用call_load_methods
,調用全部Class
和Category
的+load
方法
進行各類objc結構的初始化(註冊Objc類、初始化類對象等等)
調用C++靜態初始化器和__attribute__((constructor))
修飾的函數
到此爲止,可執行文件和動態庫中全部的符號(Class,Protocol,Selector,IMP,…)都已經按格式成功加載到內存中,被runtime 所管理
main
安裝包(IPA)主要由可執行文件、資源組成
資源(圖片、音頻、視頻等)
採起無損壓縮
去除沒有用到的資源:
可執行文件瘦身
去掉異常支持,Enable C++ Exceptions、Enable Objective-C Exceptions設置爲NO, Other C Flags添加-fno-exceptions
利用AppCode(www.jetbrains.com/objc/) 檢測未使用的代碼:
菜單欄 -> Code -> Inspect Code
編寫LLVM插件檢測出重複代碼、未被調用的代碼