Runloop
RunLoop
RunLoop就是執行迴圈,處理app中的各種事件(比如觸控事件,定時器事件,Selector事件)
一個執行緒對應一個RunLoop,主執行緒的RunLoop已經自動建立好了,子執行緒的RunLoop需要主動建立,RunLoop在第一次獲取時建立,執行緒結束時銷燬
RunLoop的獲得
- Foundation
- [NSRunLoop currentRunLoop]; // 獲得當前執行緒的RunLoop物件
- [NSRunLoop mainRunLoop]; // 獲得主執行緒的RunLoop物件
- Core Foundation
- CFRunLoopGetCurrent(); // 獲得當前執行緒的RunLoop物件
- CFRunLoopGetMain(); // 獲得主執行緒的RunLoop物件
RunLoop相關類
- Core Foundation中關於RunLoop的5個類
- CFRunLoopRef
- CFRunLoopModeRef
- CFRunLoopSourceRef
- CFRunLoopTimerRef
- CFRunLoopObserverRef
RunLoop的組成
- Mode
- Timer
- source
- Observer
Mode
Mode代表RunLoop的執行模式。每次RunLoop職能指定一個Mode執行。切換Mode職能退出Loop,再重新指定一個Mode進入。
一個 RunLoop 包含若干個 Mode,每個Mode又包含若干個Source/Timer/Observer
系統預設的5個Mode
NSDefaultRunLoopMode:App的預設Mode,通常主執行緒是在這個Mode下執行
UITrackingRunLoopMode:介面跟蹤 Mode,用於 ScrollView 追蹤觸控滑動,保證介面滑動時不受其他 Mode 影響
UIInitializationRunLoopMode: 在剛啟動 App 時第進入的第一個 Mode,啟動完成後就不再使用
GSEventReceiveRunLoopMode: 接受系統事件的內部 Mode,通常用不到
NSRunLoopCommonModes: 這是一個佔位用的Mode,不是一種真正的Mode(既執行Default中的事件也執行track中的事件)
Timer
CFRunLoopTimerRef是基於時間的觸發器
CFRunLoopTimerRef基本上說的就是NSTimer,它受RunLoop的Mode影響
GCD的定時器不受RunLoop的Mode影響
- (void)timer
{
NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];
// 定時器只執行在NSDefaultRunLoopMode下,一旦RunLoop進入其他模式,這個定時器就不會工作(比如textField的拖動)
// [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
// 定時器只執行在UITrackingRunLoopMode下,一旦RunLoop進入其他模式,這個定時器就不會工作
// [[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];
// 定時器會跑在標記為common modes的模式下
// 標記為common modes的模式:UITrackingRunLoopMode和NSDefaultRunLoopMode
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
}
- (void)timer2
{
// 呼叫了scheduledTimer返回的定時器,已經自動被新增到當前runLoop中,而且是NSDefaultRunLoopMode
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];
// 修改模式
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
}
- (void)run
{
NSLog(@"----run");
}
Source
CFRunLoopSourceRef是事件源(輸入源)
-
按照官方文件,Source的分類
- Port-Based Sources (跟其他執行緒互動,或通過核心傳送的訊息)
- Custom Input Sources (自動以輸入源,幾乎不用)
- Cocoa Perform Selector Sources (比如performSelecter等方法)
-
按照函式呼叫棧,Source的分類
- Source0:非基於Port的
- Source1:基於Port的,通過核心和其他執行緒通訊,接收、分發系統事件
事件的傳入都是先傳入Source1。然後再由Source1分發至source0進行處理。所以在函式呼叫棧中往往只看到Source0。
Obersver
CFRunLoopObserverRef是觀察者,能夠監聽RunLoop的狀態改變
- 可以監聽的時間點
/* Run Loop Observer Activities */
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
kCFRunLoopEntry = (1UL << 0), // 1
kCFRunLoopBeforeTimers = (1UL << 1), // 2
kCFRunLoopBeforeSources = (1UL << 2), // 4
kCFRunLoopBeforeWaiting = (1UL << 5), // 32
kCFRunLoopAfterWaiting = (1UL << 6), // 64
kCFRunLoopExit = (1UL << 7), // 128
kCFRunLoopAllActivities = 0x0FFFFFFFU
};
- 新增Observer
- (void)observer
{
// 建立observer
CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
NSLog(@"----監聽到RunLoop狀態發生改變---%zd", activity);
});
// 新增觀察者:監聽RunLoop的狀態
CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);
// 釋放Observer
//凡是帶有Create、Copy、Retain等字眼的函式,建立出來的物件,都需要在最後做一次release
//比如CFRunLoopObserverCreate
//release函式:CFRelease(物件);
CFRelease(observer);
}
RunLoop處理邏輯
- 1:通知觀察者run loop已經啟動
- 2:通知觀察者任何即將要開始的定時器
- 3:通知觀察者任何即將啟動的source0
- 4:啟動任何準備好的source0
- 5:如果接收到source1準備好並處於等待狀態,立即啟動,並進入步驟9
- 6:通知觀察者執行緒進入休眠
- 7:將執行緒置於休眠直到任何一下面的事件發生:
- 某一事件到達source1
- 定時器啟動
- runloop設定的時間超時
- runloop被顯式喚醒
- 8:通知觀察者執行緒將被喚醒
- 9:處理未處理的事件
- 如果使用者定義的定時器啟動,處理定時器事件並重啟runloop,進入步驟2
- 如果輸入源啟動,傳遞相應的訊息
- 如果runloop被顯示喚醒而且時間還未超時,重啟runloop,進入步驟2
- 10:通知觀察者runloop結束
相關文章
- iOS runloopiOSOOP
- RunLoop備忘OOP
- runLoop瞭解OOP
- iOS RunLoop(一)iOSOOP
- RunLoop 淺析OOP
- Runloop & 方法呼叫OOP
- iOS RunLoop 探究iOSOOP
- RunLoop-bOOP
- iOS 淺談 RunloopiOSOOP
- Runloop與performSelectorOOPperformSelector
- RunTime和RunLoopOOP
- ObjC RunLoop簡析OBJOOP
- RunLoop刨根問底OOP
- [譯]奔跑吧!RunLoop!OOP
- iOS Runloop(面試題)iOSOOP面試題
- iOS RunLoop詳解iOSOOP
- Runloop + runtime + otherOOP
- RunLoop的學習OOP
- RunLoop的前世今生OOP
- 深入理解RunLoopOOP
- iOS開發- RunLoopiOSOOP
- RunLoop總結與面試OOP面試
- RunLoop底層原理探究OOP
- RunLoop內部邏輯OOP
- RunLoop 原始碼閱讀OOP原始碼
- iOS知識梳理:RunLoopiOSOOP
- Runloop 多執行緒OOP執行緒
- OC RunLoop應用例子OOP
- iOS 底層探索之RunloopiOSOOP
- iOS底層面試題–RunLoopiOS面試題OOP
- iOS底層面試題--RunLoopiOS面試題OOP
- AutoreleasePool、Block、Runloop整理筆記BloCOOP筆記
- 底層原理探究(二)RunLoopOOP
- Hi,runloop 交個朋友吧OOP
- 多執行緒之Runloop執行緒OOP
- RunLoop常駐執行緒OOP執行緒
- Runloop-執行迴圈OOP
- iOS底層原理探究-RunloopiOSOOP