一、UITrackingRunLoopMode與NSTimer
下面的方法Timer被添加到NSDefaultRunLoopMode抡砂,在滑動(dòng)Scrollview的時(shí)候系統(tǒng)會(huì)切換至UITrackingRunLoopMode,Timer就會(huì)暫時(shí)停止.
[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerTick:) userInfo:nil repeats:YES];
當(dāng)存在 tableView/scrollView 滑動(dòng)時(shí),若不希望Timer被滑動(dòng)影響碴巾,需添加到NSRunLoopCommonMode.
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerTick:) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop]addTimer:timer forMode:NSRunLoopCommonModes];
二厦瓢、通過runloop解決在 tableView 滾動(dòng)時(shí)候停止加載圖片的需求
利用RunLoop 不同 mode 的特性低匙,可以將圖片的加載放到NSDefaultRunLoopMode的mode里顽冶,這樣在滾動(dòng)UITrackingRunLoopMode這個(gè)mode時(shí)不會(huì)被加載而影響到。
UIImage *downloadedImage = ...;
[self.avatarImageView performSelector:@selector(setImage:) withObject:downloadedImage afterDelay:0 inModes:@[NSDefaultRunLoopMode]];
三绞呈、runloop 解決在 tableView 中同時(shí)加載多個(gè)大圖的使用
runloop 中最先響應(yīng)的 UI 的繪制, tableView 在滑動(dòng)時(shí)就需要在一次 runloop 循環(huán)中繪制所有的屏幕上的圖片,如果在 cellForxxx 方法中有imageView.image = image 等代碼,這部分會(huì)非常消耗資源(尤其在圖片較大的情況),一次 runloop 執(zhí)行時(shí)間太長(zhǎng), 就會(huì)導(dǎo)致 UI 響應(yīng)變慢, 直觀感受就是 app 卡頓嚴(yán)重.
解決思路
原來是一次runloop 中繪制所有的 view 中顯示出來的圖片,那么為什么不在一次 runloop 時(shí)候只繪制一張圖片. 這樣每次 runloop 需要完成的內(nèi)容較少,UI 才不會(huì)卡頓.
具體實(shí)踐
首先封裝一個(gè)task queue,用它觀察 RunLoop 的狀態(tài), 當(dāng) RunLoop 的狀態(tài)是 kCFRunLoopBeforeWaiting,取出 queue 中的第一個(gè) task 然后執(zhí)行,然后將該 task 移除 queue. queue 中的 task 是一個(gè)個(gè)將耗時(shí)任務(wù)封裝的成的代碼塊. 在 tableView 的 cellForRowAtIndexPath 方法中,我們將 task 代碼塊加入到 queue 中,讓 queue 根據(jù) RunLoop 的狀態(tài)每次在進(jìn)入睡眠前執(zhí)行一個(gè) task.
https://github.com/diwu/RunLoopWorkDistribution
四、runloop 監(jiān)控 App 卡頓,并查找具體卡頓函數(shù)的方法
app 卡頓的定義
mainRunLoop 中一次 RunLoop 循環(huán)執(zhí)行時(shí)間過長(zhǎng),導(dǎo)致新的事件傳遞到 RunLoop 中響應(yīng)不及時(shí), 直觀感受就是卡頓.因此可以通過一定方法求出,第一次進(jìn)入 RunLoop 與第二次進(jìn)入 RunLoop 之間的時(shí)間, 如果這個(gè)時(shí)間超過某閥值,就說明 App 卡頓.
具體實(shí)踐
使用 global 線程中監(jiān)聽 mainRunLoop 的狀態(tài), 使用使用 semaphore 來進(jìn)行超時(shí)統(tǒng)計(jì)(超時(shí)時(shí)間就是 runloop 的閥值)管理. 如果連續(xù)多次超時(shí),就使用 CrashReport 打印出當(dāng)前函數(shù)調(diào)用棧的內(nèi)容.
https://github.com/suifengqjn/PerformanceMonitor
還在學(xué)習(xí)中圾亏,不足之處封拧,請(qǐng)諒解泽西!
本文轉(zhuǎn)自http://www.reibang.com/p/924cb2b218f5