這次主要講的Runloop的實(shí)際應(yīng)用,基礎(chǔ)的內(nèi)容就不在這介紹了,詳細(xì)的文章可以查看深入理解RunLoop
RunLoop 內(nèi)部的邏輯大致就是上圖的這樣.
主線程中執(zhí)行事件如滑動(dòng)事件觸摸事件等等都在3~5中執(zhí)行,如果我們將其他大量的操作都放其中肯定會(huì)導(dǎo)致界面卡頓.
其實(shí)我們也可以將一些操作放在子線程中,需要渲染時(shí)再回到線程渲染效果也是可以的.
好吧,現(xiàn)在開(kāi)始正式介紹實(shí)現(xiàn)的方法:
因?yàn)閞unloop相當(dāng)于一個(gè)while循環(huán)的東西,每當(dāng)事件都處理完之后就進(jìn)入休眠狀態(tài),當(dāng)有新的任務(wù)加入才會(huì)重新喚醒,這就是我們需要利用的地方,runloop進(jìn)入7之后說(shuō)明當(dāng)前所有的事件都已經(jīng)結(jié)束了,所以在這個(gè)時(shí)候執(zhí)行我們的需要的任務(wù)就不會(huì)影響到之前任務(wù)的刷新.
因?yàn)樘O果提供了監(jiān)聽(tīng)runloop狀態(tài)的方法,所以我可以通過(guò)監(jiān)聽(tīng)實(shí)現(xiàn)
具體實(shí)現(xiàn)可以去下載Demo
- 第一步添加runloop監(jiān)聽(tīng)
static void _registerObserver(CFOptionFlags activities, CFRunLoopObserverRef observer, CFIndex order, CFStringRef mode, void *info, CFRunLoopObserverCallBack callback) {
CFRunLoopRef runLoop = CFRunLoopGetCurrent();
CFRunLoopObserverContext context = {
0,
info,
&CFRetain,
&CFRelease,
NULL
};
observer = CFRunLoopObserverCreate( NULL,
activities,
YES,
order,
callback,
&context);
CFRunLoopAddObserver(runLoop, observer, mode);
CFRelease(observer);
}
- 蘋果提供了一下的監(jiān)聽(tīng)狀態(tài),我們可以選擇kCFRunLoopBeforeWaiting當(dāng)正要進(jìn)入休眠狀態(tài)時(shí)執(zhí)行,這樣不需要重新喚醒
/* Run Loop Observer Activities */
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
kCFRunLoopEntry = (1UL << 0),
kCFRunLoopBeforeTimers = (1UL << 1),
kCFRunLoopBeforeSources = (1UL << 2),
kCFRunLoopBeforeWaiting = (1UL << 5),
kCFRunLoopAfterWaiting = (1UL << 6),
kCFRunLoopExit = (1UL << 7),
kCFRunLoopAllActivities = 0x0FFFFFFFU
};
- 這里就是我的得到監(jiān)聽(tīng)結(jié)果之后回調(diào)的方法,我們可以將需要執(zhí)行的代碼寫到block中,然后加入數(shù)組中,每次runloop執(zhí)行結(jié)束就執(zhí)行一個(gè)
static void _runLoopWorkDistributionCallback(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info)
{
這里就是我的得到監(jiān)聽(tīng)結(jié)果之后回調(diào)的方法,我們可以將需要執(zhí)行的代碼寫到block中,然后加入數(shù)組中,每次runloop執(zhí)行結(jié)束就執(zhí)行一個(gè)
}
如解釋有誤歡迎指正~
特此鳴謝diwu大神
思路基本照搬大神的Demo,diwu大神的github大神雖然是中國(guó)人但是英文太好,文檔都是英文的,而且demo沒(méi)有寫注解,特地寫了一份帶中文注解的庫(kù),隨帶稍微優(yōu)化了性能大家也可以看看的我優(yōu)化后的庫(kù)喜歡就給個(gè)Star唄
優(yōu)化+注解后的庫(kù):https://github.com/CZXBigBrother/MCRunLoopWork,也保留了原來(lái)的庫(kù)
DWURunLoopWorkDistribution 是大神原來(lái)寫的類
MCRunloopWork 這是我優(yōu)化之后的類,添加了一些方法和配置選項(xiàng),方便在更多場(chǎng)景下使用
typedef BOOL(^MCRunLoopWorkUnit)(void);
typedef enum : NSUInteger {
MCRunLoopEntry = kCFRunLoopEntry,//進(jìn)入runloop時(shí)
MCRunLoopBeforeTimers = kCFRunLoopBeforeTimers,//執(zhí)行timer之前時(shí)
MCRunLoopBeforeSources = kCFRunLoopBeforeSources,//執(zhí)行sources之前時(shí)
MCRunLoopBeforeWaiting = kCFRunLoopBeforeWaiting,//開(kāi)始waiting之前時(shí)
MCRunLoopAfterWaiting = kCFRunLoopAfterWaiting,//開(kāi)始waiting之后時(shí)
MCRunLoopExit = kCFRunLoopExit,//退出runloop時(shí)
MCRunLoopAllActivities = kCFRunLoopAllActivities//所有的狀態(tài)
}MCRunLoopFlag;//runloop的各種狀態(tài)
typedef enum : NSUInteger {
MCRunLoopDefaultMode = 0,
MCRunLoopCommonMode
}MCRunlopMode;
/*
* 初始化
*/
+ (instancetype)sharedRunLoopWork;
/*
* 監(jiān)聽(tīng)Runloop的狀態(tài)屬性,默認(rèn)MCRunLoopBeforeWaiting
*/
@property (assign, nonatomic) MCRunLoopFlag runLoopflag;
/*
* 監(jiān)聽(tīng)Runloop的模式
* 默認(rèn)MCRunLoopDefaultMode(kCFRunLoopDefaultMode) 系統(tǒng)渲染優(yōu)先,當(dāng)系統(tǒng)渲染結(jié)束才能執(zhí)行我們需要的事件
* MCRunLoopCommonMode(kCFRunLoopCommonModes) 將timer插入runloop頂層提高優(yōu)先級(jí)(使用后切勿將耗時(shí)操作加入任務(wù),慎用)
*/
@property (assign, nonatomic) MCRunlopMode runlopMode;
/*
* 開(kāi)始監(jiān)聽(tīng)Runloop
*/
- (void)start;
/*
* 停止監(jiān)聽(tīng)Runloop
*/
- (void)stop;
/*
* 添加需要在Runloop中執(zhí)行的任務(wù)
*/
- (void)addTask:(MCRunLoopWorkUnit)unit withKey:(id)key;
/*
* 刪除所有的隊(duì)列
*/
- (void)removeAllTasks;